Home  >  Article  >  Web Front-end  >  The impact of JS, CSS and img on DOMContentLoaded event_javascript skills

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills

WBOY
WBOYOriginal
2016-05-16 16:39:571163browse

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

什么是DOMContentLoaded事件?

首先想到的是查看W3C的HTML5规范,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, The impact of JS, CSS and img on DOMContentLoaded event_javascript skillss, and subframes to finish loading
Note: Stylesheet loads block script execution, so if you have a <font face="NSimsun"><script></script></font> after a <font face="NSimsun"><link rel="stylesheet" ...></font>, the page will not finish parsing – and DOMContentLoaded will not fire – until the stylesheet is loaded.

这么看来,至少可以得出这么一个理论:DOMContentLoaded事件本身不会等待CSS文件、图片、iframe加载完成。
它的触发时机是:加载完页面,解析完所有标签(不包括执行CSS和JS),并如规范中所说的设置 <font face="NSimsun">interactive</font> 和执行每个静态的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 rel="stylesheet" type="text/css" href="./css/main.css" rel="external nofollow" rel="external nofollow" >
</head>
<body>
  <p>Content</p>
  <img  src="./img/chrome-girl.jpg" alt="The impact of JS, CSS and img on DOMContentLoaded event_javascript skills" >
</body>
</html>

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills


图一

如果页面中没有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 rel="stylesheet" type="text/css" href="./css/main.css" rel="external nofollow" rel="external nofollow" >
  <script type="text/javascript">
    console.timeStamp('Inline script after link in head');
  </script>
</head>
<body>
  <p>Content</p>
  <img  src="./img/chrome-girl.jpg" alt="The impact of JS, CSS and img on DOMContentLoaded event_javascript skills" >
  <script type="text/javascript" src="./js/main.js"></script>
</body>
</html>

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

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills

图二

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

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

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

从图二中可以看出,在CSS之前的JS立刻得到了执行,而在CSS之后的JS,需要等待CSS加载完后才执行,比较明显的是main.js早就加载完了,但还是要等main.css加载完才能执行。而DOMContentLoaded事件,则是在JS执行完后才触发。滑动Timeline面板中表示展示区域的滑块,如图三,放大后即可看到表示DOMContentLoaded事件的蓝线(之前跟黄线和绿线靠的太近了),当然,通过 console.timeStamp() 向TimeLine中添加的记录也可证明其触发时间。

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills


图三

现代浏览器会并发的预加载CSS, JS,也就是一开始就并发的请求这些资源,但是,执行CSS和JS的顺序还是按原来的依赖顺序(JS的执行要等待位于其前面的CSS和JS加载、执行完)。先加载完成的资源,如果其依赖还没加载、执行完,就只能等着。

实验3:img何时开始解码、绘制?


从图三中我们可以发现一个有趣的地方:img的请求老早就发出了,但延迟了一段时间才开始解码。如图二、图三中的红框所示,截图中只框出了一部分表示解码的记录,而实际上这些表示解码的记录一直持续到img加载结束,如图四所示,img是一边加载一边解码的:

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills


图三

现代浏览器会并发的预加载CSS, JS,也就是一开始就并发的请求这些资源,但是,执行CSS和JS的顺序还是按原来的依赖顺序(JS的执行要等待位于其前面的CSS和JS加载、执行完)。先加载完成的资源,如果其依赖还没加载、执行完,就只能等着。

实验3:img何时开始解码、绘制?

从图三中我们可以发现一个有趣的地方:img的请求老早就发出了,但延迟了一段时间才开始解码。如图二、图三中的红框所示,截图中只框出了一部分表示解码的记录,而实际上这些表示解码的记录一直持续到img加载结束,如图四所示,img是一边加载一边解码的:

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills


图四

抱着“猜想——验证”的想法,我猜想这是因为img这个资源是否需要展现出来,需要等 所有的JS和CSS的执行完 才知道,因为main.js可能会执行某些DOM操作,比如删除这个img元素,或者修改其src属性,而CSS可能会将其 <font face="NSimsun">display: none</font>

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills


图五

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills


图六

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills


图七

图五中没有JS和CSS,img的数据一接收到就马上开始解码了。
图六中没有JS,但img要等到CSS加载完才开始解码。
图七的代码跟图六的代码唯一的区别是CSS把img给 <font face="NSimsun">display: none;</font> ,这使得img虽然请求了,但根本没有进行解码。
这说明,img是否需要解码、绘图(paint)出来,确实需要等CSS加载、执行完才能知道。也就是说,CSS会阻塞img的展现!那么JS呢?

The impact of JS, CSS and img on DOMContentLoaded event_javascript skills


图八

图八对应的代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title></title>
  <script type="text/javascript">
    console.timeStamp('Inline script in head');
    window.addEventListener('DOMContentLoaded', function(){
      console.timeStamp('DOMContentLoaded event');
    });
  </script>
</head>
<body>
  <p>Content</p>
  <img  src="./img/chrome-girl.jpg" alt="The impact of JS, CSS and img on DOMContentLoaded event_javascript skills" >
  <script type="text/javascript" src="./js/main.js"></script>
</body>
</html>

It is very surprising that in a page with JS but no CSS, img can actually start decoding and drawing (paint) immediately after receiving the data. In other words, JS does not block the display of img! This is different from our previous understanding of the traditional concept that JS will block img resources. It seems that Chrome has made new optimizations for the loading and display of img.

The $(document).ready() method of jQuery that we commonly use is to monitor the DOMContentLoaded event (of course, it also provides a downgrade solution internally by simulating the DOMContentLoaded event and monitoring the onload event). It is generally recommended to register events for DOM elements when the DOMContentLoaded event is triggered. So triggering the DOMContentLoaded event as soon as possible means that the page can be made interactive as soon as possible:

Reduce the size of CSS files, divide a single CSS file into several files for parallel loading, and reduce the blocking time of CSS on JS

Secondary JS files are loaded by dynamically inserting script tags (dynamically inserted script tags do not block the triggering of the DOMContentLoaded event)

Sprites used in CSS can be loaded together with the CSS file in HTML by preloading img

During the experiment, I felt that the Timeline panel of Chrome developer tools was very powerful, and every move of the browser was recorded. In the past, if we wanted to understand and explore the internal behavior of the browser in front-end development, we would either do black box testing by feeling the stones, or study the browser source code with twice the result and half the effort. The only efficient way was to learn from other people's research experience and look at foreigners' research experience. article, but the development of browsers is changing with each passing day (for example, the JS found in this experiment does not block the display of img), other people’s experience is never the latest and most suitable. The key is to combine your own business and demand scenarios, and make targeted decisions Analysis and optimization.

PS.
The above test environment is windows/chrome, and Fiddler is used to simulate a slow network

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn