onerror 卡死页面因 404 触发无限循环,须用 dataset 标记防重;srcset 不支持 onerror 自动降级,应将 fallback 图写入 srcset 或用全局 error 事件捕获并内联 SVG。

onerror 为什么一写就卡死页面
因为备用图也 404 时,onerror 会再次触发,形成无限循环——浏览器内存暴涨、标签页无响应甚至崩溃。它不是“换张图”那么简单,而是事件链没切断。
必须加防重逻辑,且不能只靠 this.onerror = null:它在某些场景下(比如备用图加载失败后被浏览器静默拦截)可能不生效。
-
onerror="if (!this.dataset.loaded) { this.dataset.loaded = '1'; this.src = '/img/fallback.svg'; }"——用dataset标记比onerror=null更可靠 - 备用图优先用
SVG或base64内联(如data:image/svg+xml;base64,PHN2Zy...),彻底规避路径问题 - 绝对避免写成
onerror="fallback()"却没定义函数,或漏引号/分号导致 JS 解析失败、事件静默失效
响应式图片(srcset + sizes)怎么 fallback
onerror 对 srcset 无效——它只响应最终选中的那个 src,而不会感知 srcset 切换过程。一旦浏览器根据 sizes 算出要加载的 URL 并失败,才触发 onerror,但此时已无法回退到其他候选源。
- 不要指望
<img srcset="a.jpg 1x, b.jpg 2x" onerror="...">能自动切到b.jpg;它只会尝试加载匹配当前 DPR 的那一张,失败即报错 - 真正可行的降级是:把 fallback 图也写进
srcset,例如srcset="real.jpg 1x, real@2x.jpg 2x, fallback.svg 1x",并确保 fallback 是最后兜底项(尺寸小、格式兼容) - 更稳妥的做法:用 JS 检测
img.naturalWidth === 0(加载失败但未触发onerror的常见信号),再手动替换src
动态插入的响应式图片如何统一处理
用 document.addEventListener('error', handler, true) 捕获所有未被拦截的资源错误,对动态插入的 img 天然友好——它在捕获阶段命中,不依赖绑定时机。
立即学习“前端免费学习笔记(深入)”;
- 务必加类型判断:
if (e.target.tagName === 'IMG' && !e.target.dataset.handled) - 推荐 fallback 到内联 SVG:
e.target.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiPjxyZWN0IHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2YwZjBmMCIvPjwvc3ZnPg=='; - 避免用
querySelectorAll('img').forEach(...)遍历绑定——新插入的节点不会被覆盖,且无法应对 SSR 渲染后 JS 延迟执行的场景
alt 文本和 CSS 占位不是 fallback 替代方案
alt 只服务读屏器,不渲染视觉内容;background-image 多层写法(如 url(broken.jpg), url(default.png))是叠加而非兜底——两张图都会发请求,第一张失败也不会阻止第二张加载,更不会隐藏破裂图标。
- 真正要“看起来正常”,必须操作
src或用:has()(仅现代浏览器支持)配合背景占位:img:has(:not([src])) { background: #eee url(placeholder.svg); } - 如果项目需兼容 IE 或旧 Android WebView,放弃
onerror,改用IntersectionObserver+Image().onload/onerror主动探测加载状态 - 最易被忽略的是 fallback 后的 fallback:默认图本身也挂了怎么办?base64 是最后一道防线,别让它只是“理论上存在”



















