JS、CSS以及img对DOMContentLoaded事件的影响

前端的纯技术就是对规范的认知

什么是DOMContentLoaded事件?

首先想到的是查看,DOMContentLoaded事件在什么时候触发:

Once the user agent stops parsing the document, the user agent must run the following steps:
1. Set the current document readiness to “interactive” and the insertion point to undefined.
Pop all the nodes off the stack of open elements.
2. If the list of scripts that will execute when the document has finished parsing is not empty, run these substeps:
2.1 Spin the event loop until the first script in the list of scripts that will execute when the document has finished parsing has its “ready to be parser-executed” flag set and the parser's Document has no style sheet that is blocking scripts.
2.2 Execute the first script in the list of scripts that will execute when the document has finished parsing.
2.3 Remove the first script element from the list of scripts that will execute when the document has finished parsing (i.e. shift out the first entry in the list).
2.4 If the list of scripts that will execute when the document has finished parsing is still not empty, repeat these substeps again from substep 1.
3. Queue a task to fire a simple event that bubbles named DOMContentLoaded at the Document.

规范总是那么的晦涩,但至少有一点是可以明确了的,就是在JS(不包括动态插入的JS)执行完之后,才会触发DOMContentLoaded事件。

接下来看看MDN上有关DOMContentLoaded事件的文档

The DOMContentLoaded event is fired when the document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading
Note: Stylesheet loads block script execution, so if you have a <script> after a <link ...>, the page will not finish parsing – and DOMContentLoaded will not fire – until the stylesheet is loaded.

这么看来,至少可以得出这么一个理论:DOMContentLoaded事件本身不会等待CSS文件、图片、iframe加载完成。
它的触发时机是:加载完页面,解析完所有标签(不包括执行CSS和JS),并如规范中所说的设置 interactive 和执行每个静态的script标签中的JS,然后触发。
而JS的执行,需要等待位于它前面的CSS加载(如果是外联的话)、执行完成,因为JS可能会依赖位于它前面的CSS计算出来的样式。

实践是检验真理的唯一标准

实验1:DOMContentLoaded事件不直接等待CSS文件、图片的加载完成

index.html:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title></title> <link type="text/css" href="https://www.jb51.net/article/css/main.css" > </head> <body> <p>Content</p> <img src="https://www.jb51.net/article/img/chrome-girl.jpg"> </body> </html>

71fca778-a249-11e3-8824-2aae4440c857


图一

如果页面中没有script标签,DOMContentLoaded事件并没有等待CSS文件、图片加载完成。

Chrome开发者工具的Timeline面板可以帮我们记录下浏览器的一举一动。图一中红色小方框中的蓝线,表示DOMContentLoaded事件,它右边的红线和绿线分别表示load事件和First paint,鼠标hover在这些线露出灰色方框下面的一小部分时就会出现带有说明文字的tips(这交互够反人类的对吧!)。

实验2:DOMContentLoaded事件需要等待JS执行完才触发

index.html:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> console.timeStamp('Inline script before link in head'); window.addEventListener('DOMContentLoaded', function(){ console.timeStamp('DOMContentLoaded event'); }); </script> <link type="text/css" href="https://www.jb51.net/article/css/main.css" > <script type="text/javascript"> console.timeStamp('Inline script after link in head'); </script> </head> <body> <p>Content</p> <img src="https://www.jb51.net/article/img/chrome-girl.jpg"> <script type="text/javascript" src="https://www.jb51.net/article/js/main.js"></script> </body> </html>

main.js:
console.timeStamp('External script after link in body');

dcf399e8-a252-11e3-92c1-c3dbad820909

图二

如果页面中静态的写有script标签,DOMContentLoaded事件需要等待JS执行完才触发。

而script标签中的JS需要等待位于其前面的CSS的加载完成。

console.timeStamp() 可以向Timeline中添加一条记录,并对应上方的一条黄线。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgsppd.html