渲染流程(下):HTML、CSS和JavaScript,是如何变成页面的?

248 阅读2分钟

“开发者工具”的“Layers”标签,选择“document”层,来实际体验下绘制列表,如下图所示:

image.png 在该图中,区域 1 就是 document 的绘制列表,拖动区域 2 中的进度条可以重现列表的绘制过程。

从 HTML 到 DOM、样式计算、布局、图 层、绘制、光栅化、合成和显示。

image.png

完整的渲染流程大致可总结:

  1. 渲染进程将 HTML 内容转换为能够读懂的DOM 树结构
  2. 渲染引擎将 CSS 样式表转化为浏览器可以理解的styleSheets,计算出 DOM 节点的样式
  3. 创建布局树,并计算元素的布局信息
  4. 对布局树进行分层,并生成分层树
  5. 为每个图层生成绘制列表,并将其提交到合成线程
  6. 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图
  7. 合成线程发送绘制图块命令DrawQuad给浏览器进程
  8. 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上

“重排”“重绘”和“合成

image.png

如果你通过 JavaScript 或者 CSS 修改元素的几何位置属性,例如改变元素的宽度、高度等,那么浏览器会触发重新布局,解析之后的一系列子阶段,这个过程就叫 重排。无疑,重排需要更新完整的渲染流水线,所以开销也是最大的。

image.png 如果修改了元素的背景颜色,那么布局阶段将不会被执行,因为并没有引 起几何位置的变换,所以就直接进入了绘制阶段,然后执行之后的一系列子阶段,这个过程就叫重绘。相较于重排操作,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。

image.png

那如果你更改一个既不要布局也不要绘制的属性,会发生什么变化呢?渲染引擎将跳过布局和绘制,只执行后续的合成操作,我们把这个过程叫做合成。

使用了 CSS 的 transform 来实现动画效果,这可以避开重排和重绘阶段,直接在非主线程上执行合成动画操作。这样的效率是最高的,因为是在非主线程上合成,并没有占用主线程的资源,另外也避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率。

重排和重绘都是渲染进程的主线程中进行的,合成线程(图中非主线程)属于渲染进程。