onload和onerror仅对img、script等外部资源元素生效,需先设src/href再绑定;onload是资源级事件,非页面级,脚本onload含执行完成,图片仅下载解码;onerror对语法错误等静默;addeventlistener支持多监听且可设once,优于onload属性覆盖式赋值。

onload 和 onerror 不是“随便绑就能用”的属性,它们只对支持外部资源加载的元素生效(比如 <img>、<script></script>、<link>、<iframe></iframe>),且必须在设置 src 或 href 后再绑定,否则事件可能直接丢失。
onload 什么时候触发?不是页面加载完才触发
onload 是资源级事件,不是页面级。它在单个资源(如一张图、一个脚本)加载并解析执行完毕后触发——注意:脚本的 onload 还包含执行完成,而图片的 onload 只管下载和解码成功。
-
<img src="a.jpg">缓存命中时,onload可能同步触发(甚至在 JS 执行到绑定语句前就完了) -
<script src="b.js"></script>的onload保证脚本已下载、解析、执行完毕,此时才能安全调用其中导出的函数 -
window.onload是全局事件,等整个页面(含所有子资源)都加载完才触发,和元素上的onload完全不同层级
onerror 绑定后为什么有时不触发?
onerror 对网络失败、404、CORS 阻断、MIME 类型错误等有效,但对以下情况**完全静默**:
- 脚本内部语法错误(如
const a = ;)——这属于执行阶段错误,归window.onerror管 - 图片 URL 是合法但返回 200 + 空内容(比如 Nginx 默认 404 页面被配置成返回 200)
- 跨域资源未带
crossorigin属性,此时错误细节被浏览器屏蔽,onerror虽触发但event对象为空,无法判断具体原因
正确写法示例:
const img = document.createElement('img');<br>img.crossOrigin = 'anonymous'; // 关键<br>img.src = 'https://example.com/photo.png';<br>img.onerror = () => {<br> console.error('Image load failed:', img.src);<br>};<br>document.body.append(img);
addEventListener 与 onxxx 属性写法的区别
两者都能用,但行为有关键差异:
-
img.onload = handler:覆盖式赋值,多次赋值只有最后一次生效 -
img.addEventListener('load', handler):可叠加多个监听器,推荐用于需要解耦或复用逻辑的场景 - 事件名写法不同:
addEventListener用'load'(无on前缀),而属性写法必须是onload -
addEventListener支持第三个参数{ once: true },避免手动清理,适合一次性逻辑
常见误用:把 onload 当作 DOM 就绪信号
很多人想“等某张图加载完再初始化 UI”,却把 img.onload 和 DOMContentLoaded 混为一谈。实际中:
- DOM 可能早于图片就绪,此时依赖图片尺寸的布局会闪动或错位
- 图片加载失败时,
onload不触发,onerror也不一定按预期兜底(比如没设默认图) - 更健壮的做法是:先占位(如用
aspect-ratio或 skeleton),再结合img.complete+onload+onerror三态判断
例如:
function handleImage(img) {<br> if (img.complete && img.naturalWidth !== 0) {<br> renderImage(img);<br> } else {<br> img.onload = () => renderImage(img);<br> img.onerror = () => showFallback(img);<br> }<br>}
真正容易被忽略的是:资源事件不冒泡,不能委托;onload 不代表渲染完成(paint),只代表资源就绪;而 onerror 在某些浏览器中对 <link rel="stylesheet"> 支持不稳定,需额外降级处理。











