我试图理解一个简单的例子推迟。我有下面JS代码这需要5秒运行。
home.js
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
wait(5000);
我在Home.html中使用此,如下图所示:
<html>
<head>
<script defer src="home.js"></script>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
我发现,如果使用或推迟把我的脚本在body标签结束(在我的理解两者是等同的),你好世界上只有5秒后出现。但是,如果使用asnyc“世界你好”立即出现。为什么是这样?
要回答你的问题立即上MDN的Script Element文档将帮助。
推迟:
与defer属性的脚本将阻止DOMContentLoaded事件从射击,直到脚本加载和完成评估。
异步:
这表明浏览器应该,如果可能的话,异步加载脚本布尔属性。
异步脚本将不会从发射撑起DOMContentLoaded事件。
有几个好造成的DOM内容像你这样做,不会阻塞UI线程延迟一段时间后出现的方式;这是一个非常不好的做法。
从DOMContentLoaded的摘录:
同步的JavaScript暂停DOM的解析。如果你想在用户请求页面后DOM获得快速解析为可能的,你可以让你的JavaScript异步
正常的做法是将文件加载后追加DOM内容。你仍然可以做到这一点与超时,但通常从后收到asynchronous action其他一些fetch像一个响应的附加DOM的内容将被加载。
这里是一个延迟之后追加DOM含量的示例:
function wait(ms){
window.setTimeout(function() {
var element = document.createElement("h1")
element.innerText = "Hello World!"
document.body.appendChild(element)
}, ms)
}
wait(5000);
<html>
<head>
<script src="home.js"></script>
</head>
<body>
</body>
</html>
@谢尔盖的回答是好的,但并没有真正解释。下4.12.1 here的示意图示出了被指定时defer
,浏览器与脚本的执行的开始等待,直到整个HTML被解析。关键是分析不渲染。渲染开始在同一时间为递延脚本的执行,但在这种特殊情况下的脚本是在一个沉重的循环阻塞。如果wait()
功能不会阻止,呈现有机会解析完成后马上与非阻塞推迟脚本执行平行,有效更新DOM。当剧本完成后虽然DOMContentLoaded仍将被解雇。
function wait(ms){
return new Promise((resolve, reject) => {setTimeout(() => resolve(), ms)});
}
wait(3000).then(() => console.log('done'));
<html>
<head>
<script defer src="home.js"></script>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
让我们来看一看这(开放调试控制台看到输出):
test.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);
的test.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 is parsed! [2]: 'wait' started! [3]: 'wait' finished! [4]: 'DOMContentLoaded' event fired!
现在你可以看到这些步骤发生:
wait
function运行(因为它是deferred
和DOM解析后运行,但DOMContentLoaded
事件之前触发)。DOMContentLoaded
事件被触发(毕竟只有defer
脚本在它们在HTML去的顺序执行)。在DOM渲染时间可以在不同的浏览器和托管HTML文件的方式不同:在Chrome浏览器(如我的测试显示)在
http://
的DOM渲染defer
脚本运行之前的情况下,但在file:///
DOM的情况下,之后呈现defer
脚本运行他们的代码同步完成。
摘要(从评论你的问题):
defer
和async
脚本异步加载。defer
脚本将在它们被放置在HTML的顺序执行。defer
触发DOMContentLoaded
脚本将被执行。async
脚本可以被加载(如被载入最有可能的顺序)以任何顺序任何时间和运行。如果这样的脚本发生在DOM解析之前加载,你不能指望这个脚本能够找到一些HTML元素。此外,在这种情况下,浏览器不等待脚本加载和执行以触发DOMContentLoaded
事件。我不同意你的
意见
结论... defer
不使页面慢如显示在下面的动画。请注意,页面渲染开始无需等待DOM加载内容的事件:
所以,你可以自由地使用defer
或async
depending on your requirements。
然而,它看起来像Chrome启动时或之前根据页面是否被加载在网络或从文件系统中的JavaScript执行喷漆后的页面:
网络:
文件系统:
虽然我不知道为什么Chrome浏览器选择的行为是那样,我会简单地说,这是你无法控制或依赖。 defer
旨在优化JavaScript内容通过网络交付,其中大部分并不适用于文件系统。