【问题标题】:Why it show defer as async and async as defer? Get "dom parsed event" right! But there are no?为什么它将延迟显示为异步,异步显示为延迟?正确获取“dom parsed event”!但是有没有?
【发布时间】:2019-09-10 23:52:44
【问题描述】:

我有一个加载器,想研究异步和延迟时间。它是一个动态插入的外部脚本标签 - 没有内联延迟。

起初我很难理解为什么异步表现为延迟 - 它在 DOMContentLoaded 之后执行

使用 2000 个 DOM 元素,异步开始表明它可以在 DOMContentLoaded 之前执行。它从本地驱动器加载。通过从主机获取,在等待响应时异步执行脚本更有意义。这样就行了。

然后我改为测试 defer 和 surprice.. 现在我开玩笑说为什么 defer 表现为异步 - 在 DOMContentLoaded 之前执行

100000 个 DOM 元素占用了 30 多秒,脚本执行仍然发生在 DOMContentLoaded 之前。怎么了?

这是我测试过的相关部分...

loader.js

window.addEventListener('DOMContentLoaded', function() {
  console.log("DOMContentLoaded");
});


  var s = document.head.appendChild(document.createElement('script'))
//  s.async = true; s.defer = false;
  s.async = false; s.defer = true;
  s.src = "script.js"
  console.log("Fetch script");

script.js

console.log("Execute script");

index.html

<html>
  <head>
    <script src="loader.js"></script>
  </head>
  <body>

    <script>  window.ti = performance.now() </script>

    --- put here every html you can find ---

    <script>
      var n = document.getElementsByTagName('*').length
      var t = parseInt(performance.now() - ti) / 1000
      document.write("<br>Parsed " + n + " elements in " + t + " s ")
    </script>

  </body>
</html>

FF 和 Chrome 中的控制台

Fetch script
Execute script
DOMContentLoaded

在 DOM 准备好使用之前,绝不应该执行延迟脚本
现在我们遇到了 DOMContentLoaded 在 DOM 出现在屏幕上之前触发的情况。怎么样?


编辑#1

当心 DOMContentLoaded - 我想要“解析 dom 内容”!!!
(所以这是代码中的错误 - 或在我的脑海中)
更正(感谢 Pointy) - 用我的话来说......

延迟脚本在 dom 解析后执行,但 dom 仍在加载。当延迟脚本和最终事件完成时,DOMContentLoaded 会触发。

所以这是我需要的某种“DOMContentParsed”。我发现最好的是 readystatechange 事件document.readyState...

让我们用这一行扩展 loader.js:

s.onload = function(){ console.log(document.readyState) }

有了足够多的 dom,它会在 Chrome 和 Firefox 控制台中显示:

Fetch script
Execute script
loading
DOMContentLoaded

这意味着在DOM is loading! 时执行延迟脚本! 是的 - 它正在加载,直到 DOMContentLoaded。遗憾的是 readyState 没有告诉 DOM 何时被解析!我也试过了。。

document.addEventListener('readystatechange', function() {
  console.log(">>" + document.readyState); 
});

这不会在“加载”时触发,因为它已经触发了,但它在延迟脚本加载后说“交互式”,并在 DOMContentLoaded 所在的位置说“完成”(它们是否相同?),它没有更多可说的。

我没有更多关于在解析 dom 时触发的方法或事件的想法。必须在继续加载其他 dom 内容之前,才能在其他时间之前获得正确的时间标记!

没有什么可找的了!在Living Standard — Last Updated 15 April 2019 第 12.2.7 节的第一点之前没有其他内容了(甚至标题跟我开玩笑):readystatechange 应该在任何脚本之前进行“交互式”之前,但它实际上没有。为什么?

对我来说,readyState 似乎在大于 2000 个元素的本地 index.html 上有一个错误,因为我可以在它说“交互式”之前执行一个延迟脚本。现在很清楚,将 readyState 也放入脚本(我忘记了)并且它说“正在加载”,这意味着在执行时仍在加载一个大 html:

script.js

console.log("Execute script " + document.readyState);

结论有时defer表现为异步,而异步表现为defer

【问题讨论】:

  • 有足够的 html... 在控制台中我看到“执行脚本”和下一行“正在加载”,这意味着 Chrome 运行 s.defer = true; s.async = 假;尽管 DOM 正在加载!!!在两台电脑上测试。 Defer 在 Chrome 中是异步的,但不是 FF

标签: javascript performance dom-events web-performance


【解决方案1】:

the MDN page for script elementsdefer属性的定义:

此布尔属性设置为向浏览器指示脚本应在文档被解析之后但在触发 DOMContentLoaded 之前执行。

具有 defer 属性的脚本将阻止 DOMContentLoaded 事件触发,直到脚本加载并完成评估。

你看到的是预期的行为。

【讨论】:

  • 感谢您的快速答复!是否有“文档已被解析”的事件?
  • 好吧,由于defer 的工作方式,您的脚本实际上正在有效运行这一事实意味着文档已被解析。您可以通过使用defer 创建一个脚本来验证这一点,并让它检查一个带有您放置在&lt;body&gt; 末尾的某个id 的元素。如果您的脚本找到带有.getElementById() 的元素,则说明该文档已被解析。
  • “交互式”有一个早期事件,但在“执行脚本”之前都没有这样做:document.addEventListener('readystatechange', function() { console.log(document.readyState); } );
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-02
  • 1970-01-01
  • 2019-03-13
  • 2019-03-01
  • 2018-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多