【发布时间】: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