浏览器界面渲染与阻塞
本文最后更新于 2024年6月7日 下午
一个网页主要由:HTML、CSS、JavaScript、其他静态资源组成,而网页元素的结构、位置主要与其中的HTML与CSS有关,其他文件会对前两者的加载产生影响。
纯HTML网页
我们考虑最简单的情况,一个网页仅仅由HTML文件构成,那么这个网页的渲染流程如下:

-
Parser -
Render -
flow渲染完成后,若因为
DOMTree的结构发生改变,界面需要重新渲染的行为称为reflow。 -
paint渲染完成后,若因为元素的样式发生改变,界面需要重新渲染的行为称为
repaint。
步骤2完成后,也即HTML文档被完整加载并解析为DOM元素后,触发DOMContentLoaded事件。
引入CSS后

图中情况:
CSS的位置位于HTML之前时。
-
HTML解析:这其中步骤1与步骤5是异步进行的,CSS加载并不影响HTML解析为DOM元素,也即不会阻碍DOMContentLoaded事件。 -
HTML渲染:RenderTree不同于DOMTree,其中包含了元素样式的描述,这些样式都来自于CSS,所以在步骤2进行前,需要等待CSS加载完毕,因此HTML的渲染会因为CSS的引入而被阻塞。需要这样做的原因在于:若是令HTML先进行渲染,那么在CSS文件加载完成后,样式改变需要重新渲染,那么这无疑加重了网页的性能负担。CSS文件一般在Header中引入也是这个目的(使得CSS先被加载好,HTML解析完成后一次渲染完成)。
引入JavaScript

图中情况:三者的顺序为
CSS->JS->HTML时。
JavaScript存在于HTML之前时,HTML的解析都会被阻塞。
CSS若位于JavaScript之前时,CSS会阻塞JavaScript的执行。
结论
三者引入的位置影响到网页的加载速度。原则上:
CSS优先引入,为了使DOM的渲染一次完成,因此放在首部。JavaScript尽量少影响DOM的构建,因此放在底部。- 若特殊情况下,必须将
JavaScript放在首部,则需要考虑它与CSS的优先关系。既然将其放在首部,意味着它的急需在网页加载的一开始进行执行,若其不需要引用CSSOM的内容,则可以将其放在CSS之前,防止被CSS`阻塞。
其他
load 与 DOMContentLoaded
DOMContentLoaded:指的是DOM元素全部解析完成。load:则指的是网页的全部资源加载完成。
可以在DOMContentLoaded体验二者区别。

display : none 与 visibility : hidden 的区别
display : none:DOM元素不存在,手动将一个正常现实的元素改为display : none,将导致reflow事件触发。visibility : hidden:DOM元素存在只是不显示,手动将一个正常现实的元素改为visibility : hidden只是从样式上将元素隐藏,导致的是repaint事件的触发。
defer 与 async
-
相同点:
- 异步执行
- 对内联脚本不起作用
- 不能调用
document.write方法
-
不同点:
async会在load事件之前执行defer会在DOMContentLoaded之前执行