JS、CSS以及img对DOMContentLoaded事件的影响
前端的纯技术就是对规范的认知
什么是DOMContentLoaded事件?
首先想到的是查看万维网路联盟(Consortium环球网简称W3C)的HTML5规范,DOMContentLoaded事件在什么时候触发:
一旦用户代理停止解析文档,用户代理必须运行以下步骤步骤:1 .将当前文档准备状态设置为"交互式",插入点设置为"未定义"。从打开的元素堆栈中弹出所有节点。2 .如果文档解析完成后将执行的脚本列表不为空,运行这些子脚本:2.1旋转事件循环,直到文档解析完成后将执行的脚本列表中的第一个脚本设置了"准备被解析器执行"标志,并且解析器的文档没有阻止脚本的样式表。2.2执行文档解析完成后将执行的脚本列表中的第一个脚本。2.3从文档解析完成后将执行的脚本列表中删除第一个脚本元素解析(即移出列表中的第一个条目)。2.4如果文档完成解析后将执行的脚本列表仍然不为空,请从子步骤1.3开始再次重复这些子步骤。对一个任务进行排队,以激发一个简单的事件,该事件在文档中弹出一个名为"加载的内容"的气泡。
规范总是那么的晦涩,但至少有一点是可以明确了的,就是在JS(不包括动态插入的JS)执行完之后,才会触发DOMContentLoaded事件。
接下来看看MDN上有关DOMContentLoaded事件的文档:
当文档被完全加载和解析后,不需要等待样式表、图像和子帧完成加载,就可以触发DOMContentLoaded事件。注意:样式表加载块脚本执行,因此如果您在链接rel="样式表"后有一个脚本.在加载样式表之前,页面不会完成解析,并且不会触发多内容加载.
这么看来,至少可以得出这么一个理论:DOMContentLoaded事件本身不会等待半铸钢钢性铸铁(铸造半钢)文件、图片、iframe加载完成。它的触发时机是:加载完页面,解析完所有标签(不包括执行半铸钢钢性铸铁(铸造半钢)和JS),并如规范中所说的设置相互作用的和执行每个静态的脚本标签中的JS,然后触发。而射流研究…的执行,需要等待位于它前面的半铸钢钢性铸铁(铸造半钢)加载(如果是外联的话)、执行完成,因为射流研究…可能会依赖位于它前面的半铸钢钢性铸铁(铸造半钢)计算出来的样式。
实践是检验真理的唯一标准
实验1:多内容加载事件不直接等待半铸钢钢性铸铁(铸造半钢)文件、图片的加载完成
index.html:
!DOCTYPE html html lang=' zh-CN ' head meta charset=' UTF-8 ' title/title link rel='样式表type='text/css' href=' ./CSS/main。CSS ' rel='外部不跟随' rel='外部不跟随'/头体pContent/p img src=' http 3360 ./img/chrome-女孩。jpg '/body/html
图一
如果页面中没有脚本标签,DOMContentLoaded事件并没有等待半铸钢钢性铸铁(铸造半钢)文件、图片加载完成。
铬开发者工具的时间表面板可以帮我们记录下浏览器的一举一动。图一中红色小方框中的蓝线,表示DOMContentLoaded事件,它右边的红线和绿线分别表示负荷事件和先画画,鼠标盘旋在这些线露出灰色方框下面的一小部分时就会出现带有说明文字的提示(这交互够反人类的对吧!)。
实验2:多内容加载事件需要等待射流研究…执行完才触发
index.html:
!DOCTYPE html html lang=' zh-CN ' head meta charset=' UTF-8 ' title/title script type=' text/JavaScript ' console . timestamp(' head中链接前的内联脚本');window . addeventlistener(' DOMContentLoaded ',function(){ console . timestamp(' DOMContentLoaded event ');});/script link rel='样式表' type='text/css' href='。/CSS/main . CSS ' rel=' external nofollow ' rel=' external nofollow '脚本类型=' text/JavaScript ' console . timestamp(' head中链接后的Inline脚本');/script/head body PContent/p img src=' http :/img/chrome-girl . jpg ' script type=' text/JavaScript ' src=' http :/js/main . js '/script/body/html main . js : console . timestamp(' body中链接后的外部脚本');
图二
如果脚本标记是静态地写在页面中的,那么在触发之前,DOMContentLoaded事件需要等待JS执行。
而脚本标签中的JS需要等待它前面的CSS完成加载。
Console.timeStamp()可以向时间轴添加一条记录,并对应顶部的一条黄线。
从图2可以看出,CSS之前的JS是立即执行的,而CSS之后的JS需要等待CSS加载后才能执行。很明显main.js已经被加载了,但是还需要等待main.css被加载后才能执行。在执行JS之后,会触发DOMContentLoaded事件。在时间线面板中滑动代表显示区域的滑块,如图3所示。放大后,您可以看到代表DOMContentLoaded事件的蓝线(之前太靠近黄线和绿线了)。当然,通过console.timeStamp()添加到TimeLine的记录也可以证明其触发时间。
图三
现代浏览器会同时预加载CSS和JS,也就是从一开始就同时请求这些资源。但是执行CSS和JS的顺序还是原来的依赖顺序(JS的执行要等前面的CSS和JS加载执行)。首先加载的资源只能在它们的依赖项尚未加载和执行时等待。
实验三:3:img什么时候开始解码画图?
从图3中,我们可以发现一个有趣的地方:img的请求很久以前就发送了,但是在解码之前被延迟了一段时间。如图2和图3中的红色方框所示,截图中只列出了一部分代表解码的记录,但实际上,这些代表解码的记录一直持续到img加载结束。如图4所示,img在加载时进行解码:
图三
现代浏览器会同时预加载CSS和JS,也就是从一开始就同时请求这些资源。但是执行CSS和JS的顺序还是原来的依赖顺序(JS的执行要等前面的CSS和JS加载执行)。首先加载的资源只能在它们的依赖项尚未加载和执行时等待。
实验三:3:img什么时候开始解码画图?
从图3中,我们可以发现一个有趣的地方:img的请求很久以前就发送了,但是在解码之前被延迟了一段时间。如图2和图3中的红色方框所示,截图中只列出了一部分代表解码的记录,但实际上,这些代表解码的记录一直持续到img加载结束。如图4所示,img在加载时进行解码:
图四
以“猜测——验证”的思路,我猜测这是因为img是否是需要显示的资源需要等到所有的JS和CSS都执行完,因为main.js可能会执行一些DOM操作,比如删除这个img元素或者修改它的src属性,而CSS可能会显示: none。
图五
图六
图七
图5中没有JS和CSS。一旦收到img的数据,它就开始解码。图6中没有JS,但是在加载CSS之前,img不会开始解码。图7中的代码和图6中的代码唯一的区别是CSS给了img display 3360 none;它发出img请求,但根本不解码。这说明img是否需要解码和绘制,真的需要等到CSS加载并执行。也就是说CSS会屏蔽img的显示!JS呢?
图8。
对应于图8的代码:
!DOCTYPE html html lang=' zh-CN ' head meta charset=' UTF-8 ' title/title script type=' text/JavaScript ' console . timestamp(' head中的内联脚本');window . addeventlistener(' DOMContentLoaded ',function(){ console . timestamp(' DOMContentLoaded event ');});/script/head body PContent/p img src=' http :/img/chrome-girl . jpg ' script type=' text/JavaScript ' src=' http :/js/main.js'/script/body/Html非常令人惊讶。在有JS但没有CSS的页面中,img收到数据后可以立即开始解码和绘画。也就是说JS不屏蔽img的显示!这不同于传统的认为JS会屏蔽img资源的想法。Chrome似乎对img的加载和呈现进行了新的优化。
我们常用的jQuery的$(文档)。ready()方法是监视DOMContentLoaded事件(当然,它也通过模拟DOMContentLoaded事件和监视onload事件来提供降级方案)。通常建议在触发DOMContentLoaded事件时,为DOM元素注册事件。所以让DOMContentLoaded事件尽快触发意味着让页面尽快交互:
减小CSS文件的大小,将单个CSS文件分成几个文件进行并行加载,减少CSS对JS的阻塞时间。
辅助JS文件是通过动态插入脚本标签来加载的(动态插入的脚本标签不会阻止DOMContentLoaded事件的触发)。
CSS中使用的向导图可以通过预加载img与CSS文件一起加载到html中。
在实验过程中,我感觉Chrome Developer Tool的时间轴面板非常强大,浏览器的每一个动作都被记录了下来。在过去,如果我们的前端开发想要理解和探索浏览器的内部行为,或者摸着石头过河做黑盒测试,或者研究浏览器源代码事半功倍,唯一有效的方法就是学习别人的研究经验,阅读外国人的文章。但是浏览器的发展是日新月异的(比如这次实验中发现的JS并没有屏蔽img的显示),其他人的体验也并不总是最新最适合的。关键是结合自己的业务和需求场景,做出针对性的分析和优化。
PS。以上测试环境为windows/chrome,慢速网络由Fiddler模拟。
版权声明:JS、CSS以及img对DOMContentLoaded事件的影响是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。