onerror一写就卡死是因为备用图404触发无限循环,必须写成onerror="this.src='fallback.svg'; this.onerror=null;"并优先使用base64占位图确保可达。

onerror 一写就卡死,不是代码没生效,而是备用图也 404,触发了无限重试——浏览器不会自动停,必须手动切断事件链。
onerror="this.src='fallback.png'" 为什么必然卡死
这是最典型的死循环写法。只要 fallback.png 不可访问(路径错、CDN 下线、权限拒绝),浏览器就会再次触发 onerror,反复加载、失败、再触发,最终内存飙升、标签页无响应。
关键点在于:onerror 是事件,不是条件判断;它不关心新 src 是否靠谱,只管“上一次请求失败了”。
- 错误写法:
onerror="this.src='fallback.png'"→ 没有终止机制 - 正确写法:
onerror="this.src='/img/placeholder.svg'; this.onerror=null;"→ 赋值后立刻解除绑定 - 更稳妥写法:
onerror="if (!this.dataset.retried) { this.dataset.retried = '1'; this.src='/img/placeholder.svg'; }",用dataset标记状态,比this.onerror=null更易调试
动态插入的 <img> 怎么绑 onerror 才不丢事件
JS 动态创建的 <img>,如果先 appendChild() 再加 onerror,首次加载失败时事件已经错过——onerror 只在资源加载失败那一刻触发,不支持“事后补监听”。
必须在插入 DOM 前完成绑定:
- 内联写法:
img.setAttribute('onerror', "this.src='/img/placeholder.svg'; this.onerror=null;") - 或用
addEventListener('error', ...),但注意:必须在img.src赋值前绑定,否则可能漏掉首次错误 - 若用框架(如 React/Vue),避免在
mounted或useEffect中才设src,应确保onerror和初始src同步存在
为什么 base64 占位图是兜底最优解
所有路径类 fallback 都有风险:相对路径受 <base> 影响,绝对路径依赖 CDN 稳定性,跨域图受 CORS 限制。而 data:image/svg+xml;base64,... 是自包含的,不发网络请求,100% 可达。
示例 SVG 占位图(30×30 白底):
data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAiIGhlaWdodD0iMzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==
- 直接塞进
onerror:onerror="this.src='data:image/svg+xml;base64,...'; this.onerror=null;" - 体积小(几十字节),不影响首屏 HTML 大小
- 规避所有路径解析、CDN 故障、CORS、404 堆叠问题
onerror 根本不触发?先排查这三类“假失败”
onerror 不是万能钩子,它只响应“请求发出后失败”。很多“图片没显示”根本进不了这个逻辑:
-
src=""、src=" "、src="javascript:void(0)"→ 浏览器不发请求,onerror永远不触发 - CORS 阻塞(控制台报
Blocked by CORS policy)→ 请求被浏览器拦截,不算“加载失败”,onerror不触发 - 服务器返回 200 + 一张兜底图(比如 Nginx 的
error_page 404 =200 /fallback.jpg)→ 请求成功,onerror不触发
真正要盯住的,永远是原始 src 路径本身是否拼错——80% 的问题,根源不在 onerror 写得对不对,而在第一张图就压根没发出去。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











