onerror="this.src='...'; this.onerror=null"是唯一安全写法,因仅设src不切断事件会导致无限循环;fallback图须稳定加载,推荐绝对路径或base64内联;动态插入img需创建时即绑定onerror;空src、CORS阻塞、200兜底页等情况onerror不触发。

onerror="this.src='...'; this.onerror=null" 是唯一安全写法
头像图片加载失败时,只写 onerror="this.src='placeholder.svg'" 会卡死页面——因为备用图也 404,浏览器会再次触发 onerror,形成无限循环。内存暴涨、标签页无响应都是真实发生过的现象。
必须在替换 src 后立刻切断事件绑定:onerror="this.src='/img/placeholder.svg'; this.onerror=null;"。分号不能省,顺序不能调换;写成 this.onerror=null; this.src=... 会导致第一次错误仍可能重入。
fallback 图必须能稳定加载,否则等于没兜底
很多项目用相对路径或 CDN 地址做降级图,结果本地双击打开 HTML、弱网、CDN 故障时,default.png 比原图还先 404,用户看到的就是纯白块。
推荐方案包括:
- 用绝对路径,如
/assets/avatar-fallback.svg(确保 Web 服务器该路径始终可访问) - 直接内联 base64 占位图,例如
data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgdmlld0JveD0iMCAwIDQ4IDQ4Ij48Y2lyY2xlIGN4PSIyNCIgY3k9IjI0IiByPSIxOCIgZmlsbD0iI2RkZCIvPjwvc3ZnPg== - 避免使用未配
crossorigin的跨域图作为 fallback,否则 CORS 阻塞不会触发onerror,但图片照样不显示
动态插入的头像 img 元素必须提前绑定 onerror
Vue/React 中用 v-for 或 map() 渲染头像列表时,如果等 DOM 插入后再通过 querySelectorAll('img').forEach(...) 补绑 onerror,很可能第一次加载失败已发生,事件永远捕获不到。
正确做法是:
- 在创建
img元素后、插入 DOM 前,就设置img.onerror = function() { this.src = '...'; this.onerror = null; }; - 框架中优先用自定义指令(如 Vue 的
v-avatar)或组件封装,把降级逻辑收口,避免每次手动写 - 全局监听不可取:虽然
document.addEventListener('error', ...)能捕获所有img错误,但它无法区分头像和其他图片,且对background-image无效
onerror 不是万能的,有些失败它根本不会触发
头像裂图却没进 onerror?很可能是以下情况之一:
立即学习“前端免费学习笔记(深入)”;
-
src是空字符串、undefined或纯空格 —— 浏览器压根不发请求,自然无错误事件 - CORS 阻塞(比如头像来自第三方图床但没配
crossorigin="anonymous")—— 控制台报错,但onerror完全沉默 - 服务器返回 200 状态码的“兜底页”(如某些 CDN 对 404 返回一个 HTML 页面)—— 浏览器认为“加载成功”,哪怕内容是文字“Not Found”
- 图片文件头正常但数据损坏(如 JPEG 解码失败)—— 此时
img.naturalWidth === 0可检测,但需额外轮询或load后主动校验
真正健壮的头像处理,得把 onerror、crossorigin 属性、alt 语义描述、服务端一致性响应这几层都对齐,缺一不可。



















