HTML文档结构中资源加载失败的onerror捕获和自动重试策略设计

作者:袖梨 2026-07-02
onerror是HTML中唯一能在标签级捕获资源加载失败的原生钩子,但需配合显式绑定、路径级计数、清空src等操作才能安全重试。

onerror 是 HTML 中唯一能在标签级捕获资源加载失败的原生钩子,但它本身不提供重试能力,必须配合显式绑定、路径级计数和清空 src 等操作才能安全重试。

img 和 script 的 onerror 必须显式绑定且隔离作用域

直接写 onerror="retry(this)" 容易出问题:动态插入的 <img><script> 可能还没绑定回调就已触发失败;多个元素共享同一段内联脚本时,this 指向可能错乱。

  • 静态 HTML 中,给每个 <img>data-idid,例如 <img src="logo.png" data-id="logo" onerror="handleImgError(this)">
  • 动态创建时,用 addEventListener('error', handler) 替代内联属性,避免字符串拼接和执行上下文丢失
  • 不要在 onerror 里直接改 this.src——浏览器可能缓存 404 响应;正确做法是先设 this.src = '',再赋新值

window.addEventListener('error', handler, true) 是捕获 script 加载失败的唯一可靠方式

script 加载失败事件不冒泡,只在捕获阶段抛出,且不能靠 e.messagee.filename 判断(跨域脚本中为空),必须用两个条件精准识别:

  • e.target.tagName === 'SCRIPT'
  • !(e instanceof ErrorEvent)(排除 JS 运行时错误)
  • 监听代码必须放在 <head> 最顶部、内联执行,不能是外部文件,也不能用 const/let(老 IE 不兼容)
  • e.target.src 可能是相对路径,需用 new URL(e.target.src, location.href) 标准化
  • 重试前必须清空 e.target.src 再赋值,否则浏览器跳过请求

重试逻辑必须与 DOM 结构强绑定,不能靠 class 或顺序推断目标

把所有重试逻辑塞进一个函数,然后靠 class 名或索引匹配目标元素,一旦 DOM 变化就失效。可靠方案是让资源和重试入口共享唯一标识:

立即学习“前端免费学习笔记(深入)”;

  • <img>data-retry-key="user-avatar",对应按钮也加相同属性
  • fetch 失败后,在容器上设 data-status="error" 并插入带 data-target="user-list" 的按钮
  • 点击时通过 document.querySelector('[data-retry-key="' + key + '"]') 精准定位,不依赖层级或 class 名
  • 这种绑定关系必须在资源加载前就建立,不能等 onerror 触发后再动态生成按钮

重试次数和退避策略必须按 pathname 粒度控制

对同一个 URL 连续重试 10 次毫无意义,尤其当失败原因是 CDN 故障或 DNS 解析失败时。关键点在于:

  • 用对象(如 retryMaps)按 url.pathname 计数,不是按域名或整个 URL
  • 每次重试前检查当前索引是否超出备用域名数组长度,超了就终止
  • 备用域名切换时要保留原协议(url.protocol)、端口、查询参数,否则可能触发混合内容警告或丢失 token
  • 不推荐用 document.write() 插入新 <script>——它会清空整个页面,且在 DOMContentLoaded 后调用直接报错

真正容易被忽略的是:重试不是“再试一次”,而是“在明确失败原因的前提下,换一种方式再试一次”。比如视频 MEDIA_ERR_SRC_NOT_SUPPORTED 就不该重试,而该切格式;MEDIA_ERR_NETWORK 才适合指数退避。路径粒度计数、清空 src、作用域隔离——这些细节不扣准,重试就会变成无效轮询。

相关文章

精彩推荐