推迟未加载页面速度更快

问题描述 投票:3回答:4

我试图理解一个简单的例子推迟。我有下面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“世界你好”立即出现。为什么是这样?

javascript deferred-loading
4个回答
1
投票

要回答你的问题立即上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>

1
投票

@谢尔盖的回答是好的,但并没有真正解释。下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>

1
投票

让我们来看一看这(开放调试控制台看到输出):

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!

现在你可以看到这些步骤发生:

  1. DOM被加载和解析。
  2. waitfunction运行(因为它是deferred和DOM解析后运行,但DOMContentLoaded事件之前触发)。
  3. “defer`脚本完成。
  4. DOMContentLoaded事件被触发(毕竟只有defer脚本在它们在HTML去的顺序执行)。
  5. HTML渲染,但有些像样式表和图像资源可以是仍在加载。

在DOM渲染时间可以在不同的浏览器和托管HTML文件的方式不同:在Chrome浏览器(如我的测试显示)在http://的DOM渲染defer脚本运行之前的情况下,但在file:/// DOM的情况下,之后呈现defer脚本运行他们的代码同步完成。

摘要(从评论你的问题):

  • deferasync脚本异步加载。
  • defer脚本将在它们被放置在HTML的顺序执行。
  • 在DOM加载和分析之后,但之前defer触发DOMContentLoaded脚本将被执行。
  • async脚本可以被加载(如被载入最有可能的顺序)以任何顺序任何时间和运行。如果这样的脚本发生在DOM解析之前加载,你不能指望这个脚本能够找到一些HTML元素。此外,在这种情况下,浏览器不等待脚本加载和执行以触发DOMContentLoaded事件。

0
投票

我不同意你的 意见 结论... defer不使页面慢如显示在下面的动画。请注意,页面渲染开始无需等待DOM加载内容的事件:

Page load animation

所以,你可以自由地使用deferasync depending on your requirements

然而,它看起来像Chrome启动时或之前根据页面是否被加载在网络或从文件系统中的JavaScript执行喷漆后的页面:

网络:

Loaded over http:

文件系统:

Loaded over file:

虽然我不知道为什么Chrome浏览器选择的行为是那样,我会简单地说,这是你无法控制或依赖。 defer旨在优化JavaScript内容通过网络交付,其中大部分并不适用于文件系统。

© www.soinside.com 2019 - 2024. All rights reserved.