浏览器绘制页面
这篇文章的主要内容是介绍浏览器在服务器获取到HTML、CSS、JavaScript等资源后的数据解析以及页面渲染的过程。也介绍了部分React生命周期钩子(ComponentDidMount、ComponentDidUpdate)及Hooks(useEffect、useLayoutEffect)对应的调用时期。
数据解析是浏览器将数据解析为 DOM树🌲、CSSOM树🌲 的过程。
页面渲染是将可见元素的布局绘制在屏幕🖥上的过程。
在页面渲染到屏幕之前,HTML、CSS、JavaScript等必须被解析完成。
数据解析
数据解析分为两个部分:首先被完成的是构建 DOM树🌲。
DOM树
获取到HTML文件后,先处理HTML标记,构建DOM树。HTML标记分为开始结束标签、属性以及数据值。
当解析器遇到非阻塞文件,解析器就会请求这些文件并继续解析。
如果遇到阻塞文件,解析过程就会被阻塞。例如:未带有
async、defer 的JavaScript文件。
构建DOM树🌲过后,是构建CSSOM树🌲。
CSSOM树
第二个步骤是构建CSSOM树🌲,CSSOM树与DOM树是相似的,构建CSSOM树速度特别快。
接下来就开始渲染环节。
页面渲染
渲染环节包括样式、布局、绘制,有的情况下还包括合成。在数据解析过程中解析出来的DOM树🌲、CSSOM树🌲 组合形成Render树🌲,Render树计算每个可见元素的布局,然后绘制到屏幕🖥上。
页面渲染分为三个部分:第一部分就是组合成Render树🌲。
Render树
第一部是DOM树🌲 和CSSOM树🌲 组合形成Render树🌲,计算样式树或渲染树从DOM树的根开始构建,遍历每个可见节点。
display: none 不会出现在Render树上,visibility: hidden 会出现在Render树上,因为会占用空间。
Render树保存所有具有内容和计算样式的可见节点。下一步是布局。
Layout
在Render树上布局、计算每个元素的高度、宽度以及位置。
第一次确定节点的大小和位置称为布局。随后对节点大小和位置的重新计算称为回流。延迟获取到的图像会发生回流。最后一步是绘制。
其中
useLayoutEffet()、ComponentDidMount、ComponentDidUpdate就在这个阶段进行。这里可以直接调用setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。useEffect()里的函数在浏览器渲染之后在一个延迟事件中被调用。
绘制
最后一步是将各个元素绘制在页面上。
绘制可以将布局树🌲中的元素分解为多个层。
为了确保重绘的速度比初始绘制的速度更快⚡️,屏幕上的绘图通常被分解成数层。如果发生这种情况,则需要进行合成。
层确实可以提高性能,但是它以内存管理💾 为代价,因此不应作为web性能优化策略的一部分过度使用。
合成
当文档的各个部分以不同的层绘制,相互重叠时,必须进行合成,以确保它们以正确的顺序绘制到屏幕上,并正确显示内容。
当页面继续加载资产时,可能会发生回流(回想一下我们迟到的示例图像),回流会触发重新绘制和重新组合。
如果我们定义了图像🎑的大小,就不需要重新布局,只需要重新绘制需要绘制的层,并在必要时进行合成。但如果我们没有定义图像大小!从服务器获取图像后,渲染过程将返回到布局步骤开始。