onerror本身不自动重试,需手动实现带计数限制、退避延迟和缓存规避的安全重试逻辑,避免无限循环与资源浪费。

onerror 事件本身不会自动循环,必须手动控制重试逻辑
浏览器原生的 onerror 只在资源加载失败时触发一次,它不是轮询机制,也不会自动重试。所谓“用计数器控制循环”,本质是:监听失败 → 手动修改 src/href → 触发新加载 → 再次监听。关键在于避免无限递归和资源浪费。
如何安全实现带计数限制的图片重试
常见于 CDN 图片加载不稳定、临时 404 或跨域拒绝场景。直接在 onerror 里反复赋值 src 极易陷入死循环(比如网络彻底不通时)。
- 必须用闭包或 data 属性保存当前重试次数,不能依赖全局变量(多个图片会互相干扰)
- 每次重试应加退避延迟(如
setTimeout),否则瞬间打满请求 - 重试前检查是否已达上限,达到后应停止并可 fallback 到占位图或提示
- URL 需带时间戳或随机参数(如
?t=1712345678),否则浏览器可能直接返回缓存的失败响应
示例:
<img src="https://cdn.example.com/photo.jpg"
onerror="retryImage(this, 0, 3)"
alt="示例图">
<p><script>
function retryImage(img, count, maxRetries) {
if (count >= maxRetries) {
img.src = "/placeholder.png";
return;
}
const timestamp = Date.now();
img.src = <code>https://cdn.example.com/photo.jpg?t=${timestamp}</code>;
setTimeout(() => {
// 可选:这里可以再绑定一次 onerror,但更推荐复用当前函数
}, 1000 * (count + 1)); // 指数退避:1s, 2s, 3s...
}
</script>script 标签的 onerror 不能靠 src 循环重试
<script onerror="..." src="..."></script> 的 onerror 触发后,再次设置 src 不会重新执行脚本加载流程(多数浏览器会忽略)。这是容易踩的坑——你以为能重试,其实只是静默失败。
立即学习“前端免费学习笔记(深入)”;
- 正确做法是动态创建
<script></script>元素,并在onerror回调中新建一个 - 必须清除旧的
onerror绑定,否则多次重试后回调堆积 - 注意 CSP 策略可能阻止内联脚本或动态创建 script,需提前配置
script-src 'self' 'unsafe-inline'
CSS @import 和 link rel="stylesheet" 的错误不可捕获
HTML 中的 <link rel="stylesheet"> 和 CSS 内的 @import **没有 onerror 事件支持**,即使写了也不会触发。这是规范限制,不是浏览器 bug。
- 无法用计数器做 CSS 加载重试
- 可行替代:用
fetch()预加载 CSS 文本,成功后再注入<style></style>;失败则走 JS 降级逻辑 - 若必须依赖 link 标签,只能靠服务端兜底(如 Nginx 返回 200 空 CSS)或监控日志人工介入
真正难处理的从来不是怎么写循环,而是判断「该不该重试」——网络超时?权限拒绝?路径永久失效?计数器只解决表象,背后得结合状态码、响应头或业务语义做决策。



















