应将 onerror 设为 null 来确保只执行一次:在错误处理函数中先设置 fallback src,再立即执行 this.onerror = null;内联写法为 onerror="this.src='fallback.jpg'; this.onerror=null;",避免无限重试。

onerror 事件触发后如何防止无限重试
HTML 元素(比如 <img>)的 onerror 属性默认没有“只执行一次”的机制——一旦你把替换逻辑写在内联 handler 里,而新 src 又加载失败,就会再次触发 onerror,形成死循环。关键不是“怎么设置循环一次”,而是“怎么确保它只运行一次”。
给 img 绑定 onerror 后手动移除自身
最直接可靠的做法:在错误处理函数里,先完成 fallback 操作(如换 src),再立刻把自己从 onerror 上卸载掉。这样即使新地址又 404,也不会再进这个 handler。
常见错误写法:<img src="bad.jpg" onerror="this.src='fallback.jpg'">
这会无限尝试加载 fallback.jpg,如果它也不存在,就反复触发。
正确做法(内联方式):<img src="bad.jpg" onerror="this.src='fallback.jpg'; this.onerror=null;">
更推荐的写法(避免内联,利于维护):
const img = document.querySelector('img[data-fallback]');
img.onerror = function() {
this.src = this.dataset.fallback;
this.onerror = null; // ? 关键:清空 handler
};
用 try/catch 或 fetch 预检替代 onerror?不适用
onerror 是唯一能捕获资源加载失败的原生机制,try/catch 对 src 赋值无效,fetch() 检查图片存在性会引发跨域、CORS、缓存、性能等问题,且不能替代浏览器原生的加载流程。别绕路,就用 onerror + onerror = null。
注意点:
- this.onerror = null 必须在 handler 内部执行,不能延迟到 setTimeout 里(否则可能已触发多次)
- 如果用了事件委托(如监听父容器),需用 event.stopImmediatePropagation() 并配合标记位,但对单个 <img> 来说过于复杂,不推荐
- Vue/React 等框架中,应通过状态控制 src,并在 error 回调里 setState 后不再还原 error 状态,原理一致
为什么不能依赖 event.preventDefault() 或 return false
onerror 不是可取消的 DOM 事件,event.preventDefault() 和 return false 完全无效。它本质是浏览器在加载失败后调用的回调函数,没有传播阶段,也没有默认行为可阻止。唯一可控动作就是:执行完逻辑后,主动切断下一次调用链。
容易被忽略的一点:
- 某些构建工具或 CMS 会自动注入 base64 占位图或 lazyload 脚本,它们可能劫持或重写 onerror,导致 onerror = null 失效。遇到这种情况,优先检查是否已有第三方脚本干预,而不是加更多兜底逻辑
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











