渲染流程

参考文章

渲染进程

渲染程序进程负责标签页内发生的一切。 合成器和光栅线程也会在渲染程序进程内运行,以便高效、流畅地渲染页面。 渲染程序进程的核心任务是将 HTML、CSS 和 JavaScript 转换为用户可与之互动的网页。

渲染进程中的主线程会处理大多数工作,例如:

  • 解析文本字符串 (HTML),生成 DOM。
  • 计算样式
  • 布局
  • 处理图层
  • 每秒把⻚⾯画 60 次
  • 执⾏全局 JS 代码
  • 执⾏事件处理函数
  • 执⾏计时器的回调函数

Web Worker 或 Service Worker,则部分 JavaScript 将由工作器线程处理。

渲染流程

DOM构建

为什么需要构建 DOM 树?

因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。

预加载资源

网站通常使用图片、CSS 和 JavaScript 等外部资源。

加快速度,系统会并发运行**“预加载扫描程序”**。如果 HTML 文档中包含 <img> 或 <link> 等内容,预加载扫描器会查看由 HTML 解析器生成的 token,并将请求发送到浏览器进程中的网络线程。

js是如何阻止dom树构建

当HTML解析器找到 <script> 标记时,它会暂停解析 HTML 文档,并加载、解析并执行 JavaScript 代码。因为 js 可能会修改当前已经生成的dom结构。

不管该脚本是否操纵了 CSSOM,都会执行 CSS 文件下载,解析操作,再执行 JavaScript 脚本。JavaScript 会阻塞 DOM 生成,而样式文件又会阻塞 JavaScript 的执行。

样式计算(Recalculate Style)

样式计算的目的是为了计算出 DOM 节点中每个元素的具体样式,这个阶段大体可分为三步来完成:

  1. 把 CSS 转换为浏览器能够理解的结构——styleSheets。
  2. 转换样式表中的属性值,使其标准化(主要是将指标准化)。
  3. 计算出 DOM 树中每个节点的具体样式(遵守 CSS 的继承和层叠两个规则)

布局

布局是查找元素几何形状的过程。主线程会遍历 DOM 和计算出的样式,并创建包含 x y 坐标和边界框大小等信息的布局树。

布局树的结构可能与 DOM 树类似,但它仅包含与页面上可见内容相关的信息。 display: none,则该元素不属于布局树的一部分(但是,具有 visibility: hidden 的元素位于布局树中)。

分层

渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)

那么需要满足什么条件,渲染引擎才会为特定的节点创建新的图层呢?

  • 拥有层叠上下文属性的元素会被提升为单独的一层(position, z-index, filter: blur(5px), opacity
  • 需要剪裁(clip)的地方也会被创建为图层

主线程会将该信息提交到合成器线程。

图层绘制

合成器线程会把一个图层的绘制拆分成很多图块,并将每个图块发送到光栅线程。

光栅化

光栅线程会光栅化每个图块并将其存储在 GPU 内存中。

合成和显示

将图块进行光栅化后,合成器线程会收集称为“绘制四边形”的图块信息,以创建合成器帧。然后通过 IPC 将合成器帧提交到浏览器进程。

合成的优势在于,它在完成时不涉及主线程。合成器线程不需要等待样式计算或 JavaScript 执行。因此,仅合成动画被认为是实现流畅性能的最佳方式。如果需要再次计算布局或绘制,则必须涉及主线程。

总结

  1. 渲染进程将 HTML 生成 DOM树结构
  2. 将 CSS 样式表 转换成 styleSheets
  3. 创建布局树,并且计算布局信息(位置,是否显示)。
  4. 分层,生成图层树,提交给合成线程。
  5. 合成线程将图层分为多个图块,发给光栅线程。
  6. 光栅线程光栅化每个图块并存于GPU中
  7. 合成线程创建合成器帧 通过IPC提交给浏览器进程,界面更改,这些合成器帧会发送到 GPU 以在屏幕上显示。