Javascript “延迟”没有更快地加载页面
我试图用一个简单的例子来理解defer。我有下面的JS代码,需要5秒钟才能运行 home.jsJavascript “延迟”没有更快地加载页面,javascript,deferred-loading,Javascript,Deferred Loading,我试图用一个简单的例子来理解defer。我有下面的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); document.addEventListener("DOMCon
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
wait(5000);
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);
函数等待(毫秒){
var start=new Date().getTime();
var结束=开始;
同时(结束<开始+毫秒){
end=新日期().getTime();
}
}
等待(5000);
我在home.html中使用它,如下所示:
<html>
<head>
<script defer src="home.js"></script>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
你好,世界!
我发现如果使用defer或将我的脚本放在body标记的末尾(在我的理解中,两者都是等效的),helloworld只在5秒后出现。但是,如果我使用asnyc,“helloworld”会立即出现。这是为什么?要回答您的直接问题,有关MDN的文档将有所帮助 推迟: 带有defer属性的脚本将阻止加载DOMContentLoaded 事件,直到脚本加载并完成计算 异步: 这是一个布尔属性,指示浏览器应 如果可能,异步加载脚本 异步脚本不会阻止触发DOMContentLoaded事件 有几种更好的方法可以使dom内容在延迟后显示,而不会像您现在这样阻塞UI线程;这是一种非常糟糕的做法 摘自: 同步JavaScript暂停对DOM的解析。如果你想要DOM 在用户请求 页面中,您可以使JavaScript异步 通常的做法是在加载文档后追加dom内容。您仍然可以在超时的情况下执行此操作,但通常附加的dom内容会在收到响应之后加载 以下是延迟后追加dom内容的示例:
函数等待(毫秒){
setTimeout(函数(){
var元素=document.createElement(“h1”)
element.innerText=“你好,世界!”
document.body.appendChild(元素)
},ms)
}
等待(5000)代码>
让我们看看这个(打开调试控制台查看输出):
test.js
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
wait(5000);
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);
document.addEventListener(“DOMContentLoaded”),函数(事件){
log(“[4]:'DOMContentLoaded'事件已激发!”);
});
函数等待(毫秒){
log(“[2]:'wait'已启动!”);
var start=new Date().getTime();
var结束=开始;
同时(结束<开始+毫秒){
end=新日期().getTime();
}
log(“[3]:'wait'finished!”);
}
等待(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>
你好,世界!
console.log('[1]:已分析DOM!')
控制台日志:
[1]: DOM is parsed!
[2]: 'wait' started!
[3]: 'wait' finished!
[4]: 'DOMContentLoaded' event fired!
[1] :DOM已解析!
[2] :“等等”开始了!
[3] :“等等”完成了!
[4] :“DOMContentLoaded”事件已激发!
现在,您可以看到以下步骤:
加载并解析DOM
运行wait
函数(因为它是deferred
函数,在解析DOM之后但触发事件之前运行)
“延迟”脚本已完成
事件被触发(仅在所有defer
脚本按照HTML中的顺序执行之后)
HTML已呈现,但仍可以加载样式表和图像等资源李>
DOM呈现时间在不同的浏览器和应用程序中可能不同
托管HTML文件的方式:在Chrome中(如我的测试所示),在http://
的情况下,DOM是
在运行defer
脚本之前渲染,但在文件的情况下://
DOM在运行defer
脚本并完成同步代码后呈现
总结(来自评论中的问题):
[1]: DOM is parsed!
[2]: 'wait' started!
[3]: 'wait' finished!
[4]: 'DOMContentLoaded' event fired!
defer
和async
脚本是异步加载的
defer
脚本将按照它们在HTML中的放置顺序执行
defer
脚本将在加载和解析DOM之后,但在启动之前执行
async
脚本可以在任何时间加载并以任何顺序运行(最有可能的顺序是加载时的顺序)。如果在解析DOM之前加载了这样一个脚本,那么您不能期望该脚本能够在HTML中找到一些元素。此外,在这种情况下,浏览器不会等待加载并执行脚本来触发DOMContentLoaded
事件
@Sergey的回答很好,但没有真正解释。4.12.1下的示意图显示,当指定了
defer
时,浏览器会等待脚本执行的开始,直到整个HTML被解析。关键是解析没有呈现。渲染与延迟脚本的执行同时开始,但在这种特殊情况下,脚本在重循环中阻塞。如果wait()。但当脚本完成时,仍将激发DOMContentLoaded
函数等待(毫秒){
返回新承诺((解析,拒绝)=>{setTimeout(()=>resolve(),ms)});
}
等待(3000),然后(()=>console.log('done')代码>
你好,世界!
我不同意你的观察结论<代码>延迟
不会使页面变慢,如以下动画所示。请注意,页面在不等待DOM内容加载事件的情况下开始呈现:
因此,您可以自由使用延迟
或异步
然而,看起来Chrome在执行JavaScript之前或之后开始绘制页面,这取决于页面是通过网络还是从文件系统加载的:
网络:
文件系统:
虽然我不知道为什么Chrome会选择这样做,但我还是会傻笑