load/domContentLoaded事件、异步/延迟Js 与DOM解析
一、DOMContentLoaded 与 load事件
关于load和DOMContentLoaded事件,mdn对于它们是这样描述的:
DOMContentLoaded
mdn文档地址:https://developer.mozilla.org/zh-CN/docs/Web/Events/DOMContentLoaded
The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.
意思就是:当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。
load
mdn文档地址:https://developer.mozilla.org/zh-CN/docs/Web/Events/load
The load event is fired when a resource and its dependent resources have finished loading.
意思就是:当一个资源及其依赖资源已完成加载时,将触发load事件。
区别小结
简而言之,二者触发时间的区别在于:DOMContentLoaded在HTML文档被解析完成之后触发,而load是在HTML所有相关资源被加载完成后触发。
为了感受这两个事件,可以使用Chrome打开一个任意一个网页。打开控制台的Network面板。以下是FT中文网首页的Network面板Waterfall截图:

可以看到图上有两条线:一条蓝线,代表DOMContentLoaded事件,触发时间为1.50s;一条红线,代表load事件,触发时间为5.54s。
如果想要更直观地感受二者的区别,还可以点击这个页面:https://testdrive-archive.azurewebsites.net/HTML5/DOMContentLoaded/Default.html
二、HTML解析过程与DOMContentLoaded触发时机
我们已经知道DOMContentLoaded的触发时间为:当 HTML文档被加载和解析完成。那么我们还需要理解HTML的解析过程。
此处我们先只考虑同步js的情况。
1.在既没有CSS也没有JS的情况下,HTML文档的解析过程为:

DOMContentLoaded事件的触发时机为:HTML解析为DOM之后。
2.有CSS无JS的情况下,HTML文档解析过程为:

这里与1.不同的地方在于,渲染树的生成是基于DOM和CSSOM的。但是触发DOMContentLoaded的时间依然是在HTML解析为DOM后,无论此时CSS解析为CSSOM的过程是否完成。
3.当有JS时,HTML文档解析过程为:

有一个问题:关于首屏时间?
“计算这个网页从空白到出现内容所花费的时间”。那怎么计算这段时间?这段时间其实就是HTML 文档加载和解析的时间。也就是DOMContentLoaded 事件触发之前所经历的时间。
所以,对于首屏时间而言,js放在HTML文档的开头和结尾处效果是一样的而js放在结尾的目的并不是为了减少首屏时间,而是由于js经常需要操纵DOM,放在后面才更能保证找到DOM节点。待进一步探究
三、异步脚本、延迟脚本与DOMContentLoaded的关系
sync
为了与异步脚本和延迟脚本进行一个更清晰的对比,在这里先将同步脚本的情况分析一下。

如上图所示, HTML 文档被解析时如果遇见(同步)脚本,则停止解析,先去加载脚本,然后执行,执行结束后继续解析 HTML 文档。HTML文档解析完毕后触发DOMContentLoaded。
async
对此,《JavaScript高级程序设计》一书的解释是:带async的脚本一定会在load事件之前执行,可能会在DOMContentLoaded之前或之后执行。
为什么async脚本可能会在DOMContentLoaded之前或之后执行呢?或者说,为什么DOMContentLoaded事件的触发既可能在async脚本执行前、又可能在async脚本执行后呢? 这是因为,async 标签的脚本加载完毕的时间有两种情况:
情况1: HTML 还没有被解析完的时候,async脚本已经加载完了,那么 HTML 停止解析,去执行脚本,脚本执行完毕后触发DOMContentLoaded事件。如下图所示:

情况2: HTML 解析完了之后,async脚本才加载完,然后再执行脚本,那么在HTML解析完毕、async脚本还没加载完的时候就触发DOMContentLoaded事件。如下图所示:

总之, DomContentLoaded 事件只关注 HTML 是否被解析完,而不关注 async 脚本。
defer
如果 script 标签中包含 defer,那么这一块脚本将不会影响 HTML 文档的解析,而是等到 HTML 解析完成后才会执行。而 DOMContentLoaded 只有在 defer 脚本执行结束后才会被触发。
defer脚本同样包含两种情况:
情况1:HTML还没解析完成时,defer脚本已经加载完毕,那么defer脚本将等待HTML解析完成后再执行。defer脚本执行完毕后触发DOMContentLoaded事件。如下图所示

情况2:HTML解析完成时,defer脚本还没加载完毕,那么defer脚本继续加载,加载完成后直接执行,执行完毕后触发DOMContentLoaded事件。如下图所示:

注意defer情况2与async情况2的两个图非常相似,区别就在于DOMContentLoaded事件的触发时间点。
对于defer脚本,《JavaScript高级程序设计》一书的说法是:“按照h5规范,两个defer脚本会安装它们出现的先后顺序执行,两个脚本会在DOMContentLoaded之前执行。”这和我们上面的分析一致。然而,该书接下来说,“但事实上,defer脚本不一定会按顺序执行,也不一定会在DOMContentLoaded之前执行。”这是一个待再继续研究测试的问题
参考博客
Using setTimeout to speed up window.onload: https://mathiasbynens.be/notes/settimeout-onload
http://www.cnblogs.com/coco1s/p/4010310.html
你不知道的DOMContentLoaded:https://zhuanlan.zhihu.com/p/25876048
https://www.cnblogs.com/lhb25/p/how-browsers-work.html
原文:https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/
load/domContentLoaded事件、异步/延迟Js 与DOM解析的更多相关文章
- JS、CSS以及img对DOMContentLoaded事件的影响
最近在做性能有关的数据上报,发现了两个非常有意思的东西:Chrome开发者工具的Timeline分析面板,以及DOMContentLoaded事件.一个是强大的令人发指的性能分析工具,一个是重要的性能 ...
- DOMContentLoaded时间触发与js,css,img的关联
DOMContentLoaded触发原理: 1.规范总是那么的晦涩,但至少有一点是可以明确了的,就是在JS(不包括动态插入的JS)执行完之后,才会触发DOMContentLoaded事件. 2.DOM ...
- 原来 CSS 与 JS 是这样阻塞 DOM 解析和渲染的
hello~各位亲爱的看官老爷们大家好.估计大家都听过,尽量将CSS放头部,JS放底部,这样可以提高页面的性能.然而,为什么呢?大家有考虑过么?很长一段时间,我都是知其然而不知其所以然,强行背下来应付 ...
- DOMContentLoaded 事件
DOMContentLoaded 事件 字面上看,它会在dom加载完成后触发. 与window.onload事件非常相似,但有一定区别: DOMContentLoaded 事件是在文档完全加载和解析之 ...
- DOM解析和优化
DOM解析 1. css不会阻塞DOM解析(DOM Tree),但会阻塞DOM渲染(css Tree + DOM Tree -> render Tree )2. JS阻塞DOM解析,但浏览器会预 ...
- HTML load事件和DOMCOntentLoaded事件
JS高程 p14 “异步脚本一定会在页面的load事件前执行,但可能会在DOMContentLoaded事件触发之前或之后执行” 普通script标签会阻塞DOM的解析 DOMcontentLoa ...
- 移动端点击事件300ms延迟问题解决方案——fastclick.js
移动端点击事件300ms延迟的问题由来已久,如下截图 下面截图来自原文:https://www.jianshu.com/p/6e2b68a93c88 网上关于300ms延迟问题的解决方法,大致分为 3 ...
- DOMContentLoaded事件中使用异步
概述 我在之前的博文(Performance面板看js加载)中提到过,如果利用监听DOMContentLoaded事件的方式来加载js是不能优化加载的,不能够替代jquery中的ready方法,原因是 ...
- 为什么JS是单线程?JS中的Event Loop(事件循环)?JS如何实现异步?setimeout?
https://segmentfault.com/a/1190000012806637 https://www.jianshu.com/p/93d756db8c81 首先,请牢记2点: (1) JS是 ...
随机推荐
- 20145330 《网络对抗》逆向及BOF基础实践
20145330 <网络对抗>逆向及BOF基础实践 1实践说明 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显 ...
- 20145201李子璇 《网络对抗》 Web基础
1.实验后回答问题 (1)什么是表单 它在网页中主要负责数据采集功能,通过用户提交的一些数据来建立网站管理者与浏览者之间的桥梁. 两个组成部分:①HTML源代码用于描述表单(比如域,标签和浏览者在页面 ...
- Ubuntu桌面环境安装
图形程序安装 运行StartX命令检查是否已安装,若提示未安装则执行: sudo apt-get install xinit 环境管理器 GNOME: sudo apt-get install gdm ...
- A8逻辑篇1.点亮一个LED(S5PV210.A8)
一.虚拟机安装好后,我们用Fedora 双击.vmx文件,将会在虚拟机中打开 相应的生成: 这些文件 二.进入虚拟机页面 等待启动 账号选择其他 用户名:root 密码:111111 设置页面大小: ...
- Scan法求凸包
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1348 给一个半径和n个点 求圆的周长 + n个点的凸包的周长 #include<bits/std ...
- NOIP2016 T4 魔法阵 暴力枚举+前缀和后缀和优化
想把最近几年的NOIP T4都先干掉,就大概差16年的,所以来做一做. 然后这题就浪费了我一整天QAQ...果然还是自己太弱了QAQ 点我看题 还是pa洛谷的... 题意:给m个物品,每个物品有一个不 ...
- CF_400_D
codeforces_400_D 题目大意:给出n扇门,m把钥匙,和没把钥匙可以改变状态(关->开,开->关>)的门的数量及对应编号(保证每个门被两把钥匙控制),现给出n扇门的初始状 ...
- Nginx + LUA下流量拦截算法
前言 每逢大促必压测,每逢大促必限流,这估计是电商人的常态.每次大促期间,业务流量是平时的几倍十几倍,大促期间大部分业务都会集中在购物车结算,必须限流,才能保证系统不宕机. 限流算法 限流算法一般有三 ...
- HDU 4745 Two Rabbits(最长回文子序列)
http://acm.hdu.edu.cn/showproblem.php?pid=4745 题意: 有一个环,现在有两只兔子各从一个点开始起跳,一个沿顺时针,另一个沿逆时针,只能在一圈之内跳,并且每 ...
- @RequestParam注解的作用及用法
最简单的两种写法,在写接口时:加或不加@RequestParam注解的区别 第一种写法参数为非必传,第二种写法参数为必传.参数名为userId 第二种写法可以通过@RequestParam(requi ...