让我们看看这个(打开调试控制台查看输出):
测试.js
document.addEventListener("DOMContentLoaded", function(event) {
console.log("[4]: 'DOMContentLoaded' event fired!");
});
function wait(ms){
console.log("[2]: 'wait' started!");
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
console.log("[3]: 'wait' finished!");
}
wait(5000);
测试.html
<html>
<head>
<script defer src="test.js"></script>
</head>
<body>
<h1>Hello World!</h1>
<script>console.log('[1]: DOM is parsed!')</script>
</body>
</html>
控制台日志:
[1]:DOM被解析!
[2]:“等待”开始!
[3]:“等待”结束!
[4]: 'DOMContentLoaded' 事件被触发!
现在你可以看到这些步骤发生了:
- DOM 被加载和解析。
- 该
wait
函数运行(因为它deferred
在解析 DOM 之后但在DOMContentLoaded
事件触发之前运行)。
- 'defer' 脚本完成。
- 该
DOMContentLoaded
事件被触发(只有在所有defer
脚本都按照它们在 HTML 中的顺序执行之后)。
- HTML 已呈现,但某些资源(如样式表和图像)仍可加载。
DOM 渲染时间在不同的浏览器和托管 HTML 文件的方式中可能不同:在 Chrome 中(如我的测试所示),如果http://
DOM 在defer
脚本运行之前渲染,但如果file:///
DOM 在defer
脚本运行后渲染他们的同步代码就完成了。
摘要(来自您在评论中的问题):
defer
并且async
脚本是异步加载的。
defer
脚本将按照它们在 HTML 中的放置顺序执行。
defer
脚本将在 DOM 加载和解析之后执行,但在DOMContentLoaded
触发之前。
async
脚本可以随时加载并以任何顺序运行(很可能按加载顺序)。如果在解析 DOM 之前恰好加载了这样的脚本,则不能指望该脚本能够找到 HTML 中的某些元素。此外,在这种情况下,浏览器不会等待脚本加载并执行来触发DOMContentLoaded
事件。