Chrome浏览器渲染页面流程

渲染模块在执行过程中会被划分为很多子阶段,输入的HTML经过这些子阶段,最后输出像素。我们把这样的一个处理流程叫做渲染流水线。




〇、 浏览器加载资源

用户输入URL时,浏览器依赖网络模块加载html、css、js等资源数据。

一、 DOM树的构建

html解析器根据html文件,构建结点,生成DOM树。

DOM和html的内容几乎一摸一样,唯一不同的是DOM以树结构保存在内存中,可由js修改。

document.getElementsByTagName("p")[0].innerText="black";


二、样式计算

样式计算的目的是为了计算出DOM节点中每个元素的具体样式。

1、创建stylesheets(css规则树)

渲染引擎会把获取到的CSS文本全部转换为styleSheets结构中的数据,并且该结构同时具备了查询和修改功能,这会为后面的样式操作提供基础。
css样式来源主要有三种:

  1. 通过link引用的外部CSS文件
  2. <style>标记内的 CSS
  3. 元素的style属性内嵌的CSS



    而styleSheets已经把以上三种类型的样式包含进去了。

2、转换样式表中的属性值,使其标准化

CSS文本中有很多属性值,如2em、blue、bold,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值。


3. 计算出DOM树中每个节点的具体样式

涉及到CSS的继承规则和层叠规则。

继承规则:CSS继承就是每个DOM节点都包含有父节点的样式。

层叠样式:层叠是CSS的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法



总结:样式计算阶段的目的是为了计算出DOM节点中每个元素的具体样式,在计算过程中需要遵守CSS的继承和层叠两个规则。这个阶段最终输出的内容是每个DOM节点的样式,并被保存在ComputedStyle的结构内。

三、创建布局

1. 创建布局树

你可能注意到了DOM树还含有很多不可见的元素,比如head标签,还有使用了display:none属性的元素。所以在显示之前,我们还要额外地构建一棵只包含可见元素布局树。


2. 布局计算

已有了一棵完整的布局树。那么接下来,就要计算布局树节点的坐标位置。

四、分层,创建图层树

渲染引擎需要为特定的节点生成专用的图层(如一些复杂的3D变换、页面滚动,或者使用z-indexing做z轴排序等),并生成一棵对应的图层树(LayerTree)
通常情况下,并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。


五、图层绘制

图层树的构建之后,渲染引擎会对图层树中的每个图层进行绘制,输出待绘制列表,存放绘制操作命令。


六、栅格化(raster)操作,绘制

实际上绘制操作是由渲染引擎中的合成线程来完成的。
当图层的绘制列表准备好之后,

  1. 主线程会把该绘制列表提交(commit)给合成线程
  2. 合成线程会按照视口附近的图块来优先生成位图
  3. 实际生成位图的操作是由栅格化(将图块转换为位图)来执行的。

渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的,运行方式如下图所示:


image.png

栅格化过程都会使用GPU来加速生成,使用GPU生成位图的过程叫快速栅格化,或者GPU栅格化,生成的位图被保存在GPU内存中。GPU操作是运行在GPU进程中,这就涉及到了跨进程操作。



七、合成和显示

一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。
浏览器进程里面的viz的组件接收合成线程发过来的DrawQuad命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。


八、总结:

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



另外,重排和重绘:

1. 更新了元素的几何属性(重排)

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

2. 更新元素的绘制属性(重绘)

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

3.直接合成阶段

那如果更改一个既不要布局也不要绘制的属性,渲染引擎将跳过布局和绘制,只执行后续的合成操作,我们把这个过程叫做合成。
使用了CSS的transform来实现动画效果,在非主线程上合成,并没有占用主线程资源,避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率。



在优化Web性能的方法中,减少重绘、重排是一种很好的优化方式:

  1. 触发repaint reflow的操作尽量放在一起,比如改变dom高度和设置margin分开写,可能会出发两次重排
    2.通过虚拟dom层计算出操作总得差异,一起提交给浏览器。之前还用过createdocumentfragment来汇总append的dom,来减少触发重排重绘次数。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容