onerror死循环本质是备用图也404导致无限递归,必须写成this.src='fallback.svg';this.onerror=null;并用绝对路径或base64确保可达。

onerror 死循环本质是备用资源也失败,导致事件反复触发 —— 必须在替换 src 的同时立即切断事件绑定,否则浏览器卡死、内存暴涨都是真实后果。
为什么 onerror="this.src='fallback.png'" 会卡死页面
这是最常踩的坑:备用图路径本身不可达(404),浏览器加载 fallback.png 失败后再次进入 onerror,形成无限递归。不是代码“没写对”,而是 fallback 图根本没被服务器返回成功响应。
- 分号不能少:
onerror="this.src='fallback.png'; this.onerror=null;"中的分号是 JS 执行分隔符,漏掉会导致第二条语句不执行 - 顺序不能颠倒:必须先赋值
this.src,再设this.onerror=null;反过来就失去兜底意义 - 相对路径风险高:开发时用
./fallback.png,上线后若 HTML 路径变化或部署在子目录,fallback 就 404 - 空
src或undefined不触发onerror:它只响应已发出请求但失败的情况,不会捕获未发起请求的“空值”
onerror 内联写法必须加 this.onerror=null
动态绑定(如 img.onerror = handler)在 Safari 和旧 Edge 中兼容性差,真正跨浏览器可靠的只有 HTML 标签内联写法。服务端渲染输出的静态 HTML 若没带这个内联逻辑,首屏图片失败时 JS 还没加载,就彻底失去兜底能力。
- 推荐用绝对路径或 base64:
onerror="this.src='/assets/placeholder.svg'; this.onerror=null;"或更稳妥的onerror="this.src='data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAiIGhlaWdodD0iMzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg=='; this.onerror=null;" - 不要依赖
alt做视觉兜底:它只是辅助文本,不参与渲染流程,无法替代图像内容 -
<picture></picture>里的<img>不是可选层:如果<img src>本身也 404,最终只显示alt,页面留白
动态插入的 <img> 怎么安全绑定 onerror
用 appendChild() 插入前没绑定 onerror,首次加载失败事件就直接丢失——因为 DOM 插入瞬间浏览器可能已开始请求,等 JS 绑定完成时错误早已发生。
- 必须在插入 DOM 前手动赋值:
const img = document.createElement('img'); img.onerror = () => { img.src = '/fallback.jpg'; img.onerror = null; }; img.src = 'original.jpg'; container.appendChild(img); - 全局监听更可靠(尤其大量动态图):
document.addEventListener('error', e => { if (e.target.tagName === 'IMG' && !e.target.dataset.handled) { e.target.dataset.handled = '1'; e.target.src = 'data:image/png;base64,...'; } }, true),注意要用捕获阶段(第三个参数true) - 慎用
display: none包裹容器:Safari 和多数 Android WebView 会跳过该元素,即使后来display改回来也不会触发加载
真正容易被忽略的是 fallback 资源本身的可用性 —— 它不是“随便写个路径就行”,而是必须和主图一样经受 CDN、路径解析、协议(file:// vs http://)、部署结构的考验。本地双击打开 HTML 文件时,/fallback.png 会被解析成系统根目录,这种失败不会报错,但 onerror 也不会触发,因为请求压根没发出去。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











