浏览器界面渲染与阻塞
本文最后更新于 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
之前执行