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

2023-10-25 16:18

本文主要是介绍JS、CSS以及img对DOMContentLoaded事件的影响,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

什么是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, images, and subframes to finish loading
Note: Stylesheet loads block script execution, so if you have a <script> after a <link rel="stylesheet" ...>, 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 rel="stylesheet" type="text/css" href="./css/main.css">
</head>
<body><p>Content</p><img src="./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 rel="stylesheet" type="text/css" href="./css/main.css"><script type="text/javascript">console.timeStamp('Inline script after link in head');</script>
</head>
<body><p>Content</p><img src="./img/chrome-girl.jpg"><script type="text/javascript" src="./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中添加一条记录,并对应上方的一条黄线。

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

910b5c2c-a253-11e3-995d-e19fb254cf4e
图三

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

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

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

7384a57a-a256-11e3-9c4a-b857956eaeed
图四

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

image
图五

image
图六

image
图七

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

image
图八

图八对应的代码:

<!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"><script type="text/javascript" src="./js/main.js"></script>
</body>
</html>

非常令人惊讶,在有JS而没有CSS的页面中,img居然能够在收到数据后就立刻开始解码、绘图(paint),也就是说,JS并没有阻塞img的展现!这跟我们以前理解的JS会阻塞img资源的传统观念不太一样,看来Chrome对img的加载和展现做了新的优化。


我们常用的jQuery的 $(document).ready() 方法,就是对DOMContentLoaded事件的监听(当然,其内部还会通过模拟DOMContentLoaded事件和监听onload事件来提供降级方案)。通常推荐在DOMContentLoaded事件触发的时候为DOM元素注册事件。所以尽快的让DOMContentLoaded事件触发,就意味着能够尽快让页面可交互:

  1. 减小CSS文件体积,把单个CSS文件分成几个文件以并行加载,减少CSS对JS的阻塞时间
  2. 次要的JS文件,通过动态插入script标签来加载(动态插入的script标签不阻塞DOMContentLoaded事件的触发)
  3. CSS中使用的精灵图,可以利用对img的预加载,放在html中跟CSS文件一起加载

在做实验的过程中,感觉Chrome开发者工具的Timeline面板非常强大,浏览器的一举一动都记录下来。以前我们前端开发要想理解、探索浏览器的内部行为,或者摸着石头过河的做黑盒测试,或者事倍功半的研究浏览器源码,唯一高效点的做法就是学习别人的研究经验,看老外的文章,但浏览器的发展日新月异(比如这次实验发现的JS不阻塞img的展现),别人的经验始终不是最新、最适合的,关键是要结合自己的业务、需求场景,有针对性的做分析和优化。


PS.

以上测试环境为windows/chrome,并用Fiddler模拟慢速网络

 

转自:http://www.alloyteam.com/2014/03/effect-js-css-and-img-event-of-domcontentloaded/

越来越懒了,转载文章里的图片都懒得下载上传了。

这篇关于JS、CSS以及img对DOMContentLoaded事件的影响的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/283717

相关文章

HTML5 中的<button>标签用法和特征

《HTML5中的<button>标签用法和特征》在HTML5中,button标签用于定义一个可点击的按钮,它是创建交互式网页的重要元素之一,本文将深入解析HTML5中的button标签,详细介绍其属... 目录引言<button> 标签的基本用法<button> 标签的属性typevaluedisabled

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

CSS Anchor Positioning重新定义锚点定位的时代来临(最新推荐)

《CSSAnchorPositioning重新定义锚点定位的时代来临(最新推荐)》CSSAnchorPositioning是一项仍在草案中的新特性,由Chrome125开始提供原生支持需... 目录 css Anchor Positioning:重新定义「锚定定位」的时代来了! 什么是 Anchor Pos

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

全面解析HTML5中Checkbox标签

《全面解析HTML5中Checkbox标签》Checkbox是HTML5中非常重要的表单元素之一,通过合理使用其属性和样式自定义方法,可以为用户提供丰富多样的交互体验,这篇文章给大家介绍HTML5中C... 在html5中,Checkbox(复选框)是一种常用的表单元素,允许用户在一组选项中选择多个项目。本

HTML5 搜索框Search Box详解

《HTML5搜索框SearchBox详解》HTML5的搜索框是一个强大的工具,能够有效提升用户体验,通过结合自动补全功能和适当的样式,可以创建出既美观又实用的搜索界面,这篇文章给大家介绍HTML5... html5 搜索框(Search Box)详解搜索框是一个用于输入查询内容的控件,通常用于网站或应用程