onerror中直接改src会导致无限循环,因备用图404会再次触发onerror,必须写成this.src='fallback.png'; this.onerror=null切断事件;它仅响应真实网络失败,不触发于空src、CORS阻塞或200兜底页。

onerror里直接改src为什么会导致无限循环
因为浏览器对加载失败的资源会触发一次 onerror,但如果备用路径(比如 this.src = 'fallback.png')也 404,就会再次触发同一事件——this.src 被反复赋值,onerror 反复执行,内存暴涨甚至页面卡死。
这不是逻辑写错,而是没切断事件绑定。必须在替换后立刻让该元素失去响应能力:
-
onerror="this.src='fallback.png'; this.onerror=null"是最低限度安全写法 - 更稳妥的是加路径判断:
onerror="if (!this.src.includes('fallback')) { this.src='fallback.png'; this.onerror=null; }" - 若 fallback 图也不可信,直接用 base64 占位:
this.src='data:image/png;base64,iVBORw0KGgo...'
动态创建的 img 怎么安全绑定 onerror
用 img.onerror = handler 或 addEventListener('error', ...) 在部分 Safari 和旧 Edge 中可能完全不触发——内联写法才是跨浏览器唯一可靠方式。
动态插入时,必须在元素插入 DOM 前 就完成绑定,否则可能来不及捕获首次失败:
立即学习“前端免费学习笔记(深入)”;
- 不要:
const img = new Image(); img.src = url; img.onerror = handler; document.body.appendChild(img);(太晚) - 要:
const img = new Image(); img.onerror = handler; img.src = url; document.body.appendChild(img); - 或更彻底:用
document.createElement('img')+setAttribute('onerror', '...')模拟内联行为
哪些情况 onerror 根本不会触发
很多人反复检查 onerror 却没反应,是因为根本没进入这个流程——它只响应“发出了请求但失败”,不是所有“图没显示”都算。
以下场景 onerror 完全沉默:
-
src为空字符串、undefined或纯空格:浏览器压根不发请求 - 跨域图片未配
crossorigin="anonymous":控制台报Blocked by CORS policy,但onerror不触发 - 服务器返回 200 状态码的兜底图(如 CDN 自动返回占位图):浏览器认为“成功加载”
- 图片文件头正常但数据损坏(如截断 JPEG):行为不一致,Chrome 可能触发,Safari 可能不触发
全局 error 监听怎么避免误伤正常逻辑
document.addEventListener('error', handler, true) 能捕获所有资源错误,但它也混着脚本执行错误、Promise 拒绝等,必须严格过滤。
只处理图片加载失败的最小判断组合是:
-
e.target.tagName === 'IMG'—— 锁定目标类型 -
!(e instanceof ErrorEvent)—— 排除 JS 运行时错误(ErrorEvent是window.onerror的类型) -
e.target.dataset.handled !== '1'—— 防重复处理(手动标记已处理)
别在 handler 里调 location.reload(),用户可能刚输完半页表单;也别无差别重试所有失败请求,得按 new URL(e.target.src, location.href).pathname 做路径级计数,超两次就切 base64 或静默降级。



















