浏览器是如何渲染一个页面的?

渲染流程

浏览器渲染流程

  • JavaScript: 构建 DOM + CSSOM
  • Style: 构建 Render Tree

DOM

Document Object Model 通过在内存中表示文档结构,将网页连接到脚本或编程语言。 DOM 使用逻辑树来表示一个文档结构。树的每一个分之都以一个节点结尾,并且每个节点都包含对象。 DOM 方法允许以编程方式访问树,使用这些方法可以更改文档的结构、样式或内容。DOM 上的节点并不一定总是 HTML 元素,当浏览器创建 DOM 树时,它还将诸如注释、属性、文本之类的内容另存为树中的单独节点。

  • 构建 DOM 的过程中遇到不携带 asyncdefer<script> 标签,浏览器会停止 DOM 的构建,等待 JS 的下载和执行。
  • 构建 DOM 的过程中携带 async<script> 标签下载完毕后,浏览器会停止 DOM 的构建,等待 JS 的执行。

CSSOM

CSS Object Model 允许通过 JavaScript 操纵 CSS,它非常类似于 DOM。CSSOM 和 DOM 是相互独立的。CSSOM 的构建过程类似于 DOM 的构建,不过它依赖的是样式结构,而不是文档结构。

CSSOM 的构建会阻塞浏览器下载&执行 JS。

Render

Render Tree 是将 DOM 和 CSSOM 结合在一起而生成的树状结构。通过 Render Tree 可以知道在每个节点上应用哪些样式规则,但是无法知道这些节点的确切位置及大小信息。在 Render Tree 被构建出来之前,页面上不会呈现任何内容。

  • display: none 的元素不会出现在 Render Tree 中。
  • 伪元素会出现在 Render Tree 中。

Layout

Layout Tree 是在 Render Tree 的基础上,为每个节点计算其布局信息,从而构建出的树状结构。

避免在通过 CSSOM 设置完样式后立刻对其进行访问,因为这样要求浏览器在你访问样式时返回最新的样式信息,相当于要求浏览器立刻进入 layout 阶段,从而造成不必要的性能损耗(本来可以在下一帧再更新样式的)。

Paint

在这一阶段需要了解两个概念:layer 和 rasterization。Layer 让浏览器知道以何种顺序去渲染相互层叠的元素,同时帮助浏览器在网页的整个生命周期中更有效执行的 paint 操作。Rasterization 是对每一个 layer 进行栅格化,使得浏览器以更高效的方式进行 paint 操作。

Compositing

利用计算好的 layer 和每一层 layer 内的栅格,组合出 viewpoint 内应该展示的页面。

first paint

为了更好的用户体验,浏览器不一定非要等到 DOM 和 CSSOM 构建完,才开始页面的渲染。可以参考 Chrome的First Paint 的思路自己在浏览器的 performance 面板中观察下实际的效果。

最佳实践是将 <link rel="stylesheet"> 标签放在 <head> 中,将 <script> 标签放在 </body> 前。当然如果你为 <script> 标签添加 asyncdefer 属性的话,将它们放在 <head> 中也是可以的。

详细的原理可以参考 How the browser renders a web page? — DOM, CSSOM, and Rendering

优化方法

  • 使用 requestAnimationFrame() 代替 setTimeout()setInterval()
  • 避免 long task 的出现。
  • 使用 Web Worker。
  • 减少样式选择器的复杂度。
  • 避免 强制同步布局

参考文献



感谢您的阅读,如果发现文章中有错误或漏洞,请批评指正。
邮箱:aadonkeyz@gmail.com

0%