onerror中直接换src会导致无限循环卡死,因fallback图加载失败会再次触发onerror;必须在三种时机设this.onerror=null,且fallback应使用编码正确的base64 SVG占位图。

onerror里直接换src为什么会导致页面卡死
因为备用图(fallback.png)本身加载失败时,onerror会再次触发——而你没切断它,于是第二次执行又走一遍 this.src = 'fallback.png',无限循环。浏览器栈迅速溢出,轻则卡顿,重则崩溃。
必须写this.onerror = null的三个时机
不是“建议”,是硬性要求。以下三种情况漏掉任一,都可能递归:
- 在内联
onerror属性中替换src后,立刻加this.onerror=null - 用
addEventListener('error', handler)绑定时,handler 内部必须手动移除监听:el.removeEventListener('error', handler) - 动态创建
img元素后,若首次加载失败并替换了src,后续不能再复用同一 handler,否则 fallback 图失败时无防护
base64占位图比相对路径更安全
用相对路径(如 './fallback.png')当降级图,仍要走一次 HTTP 请求——而这次请求也可能 404 或跨域失败。真正防住递归的最后一道防线,是 fallback 本身不依赖网络:
- 用最小 base64 SVG 占位,例如:
data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"><rect width="1" height="1" fill="%23f0f0f0"></rect></svg> - 确保 URL 编码正确(空格、引号、
/都要转义),否则 base64 字符串解析失败也会进onerror - 不要把 base64 放进 JS 变量再拼到
src,避免字符串截断或编码丢失;直接写在 HTML 属性里最稳
动态插入图片时,别用内联onerror
JS 动态生成 img 元素时,如果还写 onerror="..." 字符串拼接,容易因引号嵌套、转义错误、this 指向错乱导致逻辑失效。此时应改用事件监听:
立即学习“前端免费学习笔记(深入)”;
- 创建元素后立即绑定:
img.addEventListener('error', e => { e.target.src = fallbackDataUrl; e.target.removeEventListener('error', arguments.callee); }) - 注意:不能用箭头函数捕获
arguments.callee,得用命名函数或显式存 handler 引用 - 更稳妥的做法是:先设
img.src = '',再赋真实地址,避免某些浏览器对已失败的src缓存响应,跳过二次请求
this.onerror = null,如果 fallback 资源是通过 CSS background-image 或伪元素注入的,那它根本不会触发 onerror——这种方案看似绕开了递归,实则放弃了对降级资源本身的加载状态控制。要不要兜底,得看业务是否允许“假成功”。



















