标准答案
- DOMContentLoaded 在 HTML 文档解析完成、DOM 树构建完成后触发,不需要等待图片、iframe、样式背景图等外部资源全部加载完成。
- load 事件会等页面和依赖资源加载完成后触发,通常比 DOMContentLoaded 更晚。需要读取图片真实尺寸或等待所有资源时才更关注 load。
- 同步 script 放在 head 里会阻塞 HTML 解析,脚本执行时可能访问不到后面的 DOM,也可能拖慢首屏。
- script 放在 body 底部可以让前面的 DOM 先解析出来。现代项目更常用 defer 或 type="module",让脚本下载不阻塞解析,并在 DOM 解析完成后按顺序执行。async 下载完成后会尽快执行,不保证顺序。
题目解析
选择事件时机要看代码需要什么资源。如果只需要操作 DOM 节点,DOMContentLoaded 或 defer 通常足够;如果依赖图片、iframe 等资源加载结果,再考虑 load。
defer 脚本会在文档解析完成后、DOMContentLoaded 前执行,并保持多个 defer 脚本的顺序。type="module" 默认具有类似 defer 的行为。
async 适合不依赖 DOM 顺序、不依赖其它脚本顺序的独立脚本,例如部分统计脚本。业务主入口如果依赖执行顺序,通常不要随意改成 async。
代码示例
下面示例对比 DOMContentLoaded、load,以及 defer 脚本和底部脚本的常见位置。
HTML
<!doctype html>
<html lang="zh-CN">
<head>
<script defer src="/app.js"></script>
</head>
<body>
<button id="save">保存</button>
<script>
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('#save').disabled = false
})
window.addEventListener('load', () => {
console.log('页面资源已加载完成')
})
</script>
</body>
</html>常见误区
- 误以为 DOMContentLoaded 要等图片全部加载。
- 在 head 同步脚本中直接操作后面的 DOM。
- 混淆 defer 和 async 的执行顺序。