window 的 onload 事件对于前端童鞋来说肯定是熟的不能再熟了,相信大家在刚入门时,见的最多的可能就是 load 事件了。load 事件接触多了,大家就会接触到它的闺蜜 DOMContentLoaded 事件,网上有很多介绍这两个事件的文章,对们它的解释无外乎以下两种
MDN的解释:load 应该仅用于检测一个完全加载的页面,当一个资源及其依赖资源已完成加载时,将触发load事件。
意思是页面的html、css、js、图片等资源都已经加载完之后才会触发 load 事件。
MDN 的解释:当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。
意思是HTML下载、解析完毕之后就触发。看了这两个解释,我仍然一脸懵逼,只是像小学生背课文一样知道 load 和 DOMContentLoaded 事件的触发时机,但还是不明白究竟什么情况下触发这两种事件。我们从头开始捋一下。
当我们输入一个页面地址时,发生了哪些事情呢?
body 里的情况比较多,body 里有可能只有 DOM 元素,有可能既有 DOM、也有 css、js 等资源,也可能只有 js 或者 css 资源,js 资源又有可能异步加载 图片、css、js 等,DOM 结构不同,浏览器的解析机制也不同,我们分开来讨论。
测试代码如下
<body> <!-- 白屏 --> <div></div> <!-- 白屏 --> <link rel="stylesheet" href="./c1.css" /> <!-- 白屏 --> <link rel="stylesheet" href="./c3.css" /> <!-- 首次渲染,页面上已经有 div1 元素了,样式是 c1.css 和 c3.css 的并集。--> <!--此时下面的 js 阻塞了 DOM 树的构建,所以下面的 div2 没有在文档的 DOM 树中,页面上看不到 div2 元素。 --> <script src="http://test.com:9000/mine/load/case2/j1.js "></script> <!-- j1.js 执行完毕,继续 DOM 解析,div2 被构建在文档 DOM 树中,此时页面上有了div2 元素,样式仍然是 c1.css 和 c3.css 的并集 --> <link rel="stylesheet" href="./c4.css" /> <!-- c4.css 加载完毕,重新构建render树,样式变成了 c1.css、c3.css 和 c4.css 的并集 --> <div></div> <script> // 利用 performance 统计 load 加载时间。 window.onload=function(){console.log(performance.timing.loadEventStart - performance.timing.fetchStart);} </script></body>
大家可以调整资源摆放位置,观察浏览器的解析表现。
上面只是讲了 html 文档的加载与渲染,并没有讲 DOMContentLoaded 事件的触发时机。直截了当地结论是,DOMContentLoaded 事件在 html文档加载完毕,并且 html 所引用的内联 js、以及外链 js 的同步代码都执行完毕后触发。
大家可以自己写一下测试代码,分别引用内联 js 和外链 js 进行测试。
当页面 DOM 结构中的 js、css、图片,以及 js 异步加载的 js、css 、图片都加载完成之后,才会触发 load 事件。
注意:
大家可以在 chrome 中试一下。
浏览器对同一域名下的资源并发下载线程数,chrome 为6个。
这里要注意关键词:同一域名。如果 n 个不同域名的话,是可以达到 n * 6 个的最大并发的下载的。
另外,load 事件与 DOMContentLoaded 事件触发所花费的时间,可以利用 performance 这个对象的一些属性进行统计,时间精确到纳秒级。一些大公司的性能统计也主要利用这个对象的数据进行上报。