DOMContentLoaded 和 load 触发时机不同:前者在 DOM 树就绪时触发,不等资源加载;后者需所有资源(含图片、CSS、iframe)加载完成。正确写法是 addEventListener("DOMContentLoaded", handler) 或将脚本置于 </body> 前;load 仅适用于 img、iframe 和 window 等特定场景。

DOMContentLoaded 和 load 不是“谁更好”,而是触发时机根本不同:前者等 DOM 树就绪(不等图片、样式表、iframe 加载),后者等整个页面资源全部加载完成。选错会直接导致脚本执行过早或过晚——比如用 load 绑定按钮点击事件,用户点不动;用 DOMContentLoaded 操作还没加载完的 <img> 尺寸,拿到的是 0。
DOMContentLoaded 触发时机与正确写法
它在 HTML 解析完成、DOM 树构建完毕后立即触发,此时 <script>、<link rel="stylesheet">、<img> 都可能还在下载中。浏览器保证此时 document.body、document.getElementById() 等可安全访问。
正确写法只有两种可靠方式:
- 使用
addEventListener("DOMContentLoaded", handler)—— 推荐,支持多次绑定 - 把脚本放在
</body>前,不加任何监听(此时 DOM 已就绪) - 避免用
document.onreadystatechange判断readyState === "interactive",行为不一致,IE/Edge 有坑
错误示例:window.onload = handler 或 document.addEventListener("load", handler) —— 这俩根本不会触发 DOMContentLoaded。
立即学习“前端免费学习笔记(深入)”;
load 事件只在特定元素上可靠
load 是个“资源加载完成”事件,但**它不会在 document 上按预期触发 DOM 就绪**。对 document 使用 load 是常见误解:它实际要等所有子资源(含 CSS、JS、图片、iframe)全部 loaded,且 CSSOM 构建完毕,耗时远长于 DOMContentLoaded。
真正该用 load 的场景只有这些:
-
<img>元素:判断图片是否加载成功,再操作尺寸或显示占位符 -
<iframe>:确保子页面 DOM 可访问 -
window:需要等所有资源就绪才执行逻辑(如统计首屏渲染完成时间)
注意:link[rel="stylesheet"] 的 load 事件不可靠(Firefox 不支持),应改用 document.styleSheets[i].cssRules 检测或监听 onload + onerror 回退。
常见踩坑:CSS 阻塞 DOMContentLoaded?
很多人以为“把 <link> 放 head 就会延迟 DOMContentLoaded”,其实不是 CSS 本身阻塞,而是**浏览器为避免 FOUC,会暂停 DOM 解析直到首个 CSS 文件开始下载并解析出 CSSOM**。所以关键在“首个 CSS 是否阻塞了 HTML 解析”。
实操建议:
- 把
<link rel="stylesheet">放在<head>里没问题,现代浏览器会预加载 - 绝对不要用
@import在 CSS 里引入其他样式表——它会串行阻塞,显著拖慢 DOMContentLoaded - 内联关键 CSS(Critical CSS),把非首屏样式用
media="print" onload="this.media='all'"异步加载
验证方法:打开 Chrome DevTools → Network → 刷新页面,看 DOMContentLoaded 时间点是否卡在某个 CSS 请求之后。
要不要用 jQuery 的 $(document).ready()?
如果你项目还在用 jQuery 3.x 以下版本,它内部模拟 DOMContentLoaded 的兼容层(比如 IE8 用 doScroll)确实有用;但 jQuery 3+ 已直接委托给原生 addEventListener("DOMContentLoaded")。此时再包一层,只是多一次函数调用开销。
更现实的问题是:团队里有人写 $(document).ready(() => {...}),有人写 document.addEventListener("DOMContentLoaded", () => {...}),混用容易漏掉重复绑定或移除逻辑。统一用原生 API 更可控,也省去 jQuery 的加载成本。
顺带一提:DOMContentLoaded 不冒泡,不能委托;而 load 在 window 上也不冒泡,但能在 <img> 上用事件委托(需手动绑定)。



















