分层 生层分层树
页面中可能有很多复杂的效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一个对应的图层树 LayerTree。
通常情况下,布局树并不是每一个节点都是包含一个图层。如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。
图层绘制 生成绘制列表
完成图层树的构建后,渲染引擎会对图层树中的每个图层进行绘制。
开发者工具中 Layers 标签tab下,选择 document,可观察到绘制列表和绘制进度,根据进度拖拽可浮现绘制过程。
栅格化操作 将图块转换为位图
绘制列表只是用来记录绘制顺序和绘制指令的列表,实际上绘制操作是有渲染引擎中的合成线程来完成的。
当图层的绘制列表准备好之后,主线程会把绘制列表提交给合成线程。
合成线程会将图层划分为图块,合成线程会按照视口附近的图块有限来生成位图,实际生成位图的操作是由栅格化来执行的。
所谓栅格化,是指将图块转换为位图。图块是栅格化执行的最小单位。
渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的。
栅格化过程通常都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫做快速栅格化 或者 GPU 栅格化,生成的位图保存在 GPU 内存中。这里涉及到了跨进程操作,GPU 进程。
合成与显示 发送绘制图块命令给浏览器进程,浏览器进程根据信息生成页面并显示在显示器
一旦所有的图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。
浏览器进程里面有一个叫 viz 的组建,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。
渲染流水线总结
<aside> 💡 0. 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
</aside>
相关概念
重排:更新了元素的几何属性
如果改变了元素的宽度、高度等几何位置属性,浏览器就会出发重排,解析之后的一系列子阶段都会重新执行,开销最大。
重绘:更新了元素的绘制属性
通过 JavaScript 改变某些元素的颜色,没有引起几何位置属性变化,布局阶段将不会被执行,直接进入绘制阶段,然后执行之后的一系列子阶段。相较于重排,省去了布局和分层阶段,执行效率会比重排高一些。
直接合成阶段:
改变一个既不要布局也不要绘制的属性,渲染进程将跳过布局和绘制,只执行后续的合成操作。
如使用 CSS 的 transform 来实现动画效果,可以避开重排和重绘阶段,直接在非主线程上执行合成动画操作。