什么是关键渲染路径 (critical rendering path)?

2024年9月7日

💎 加入 E+ 成長計畫 如果你喜歡我們的內容,歡迎加入 E+,獲得更多深入的軟體前後端內容

身为前端工程师,关键渲染路径 (critical rendering path) 是在开发时,经常需要打交道的一条路径,也是业界做效能优化分析时,经常会提到的一条路径。

所谓的关键渲染路径,是浏览器从下载 HTML、CSS、JavaScript 等文件,到把这些文件转换成使用者可以看、可以互动的网页的过程。

什么是关键渲染路径?

所谓的关键渲染路径,是浏览器从下载 HTML、CSS、JavaScript 等文件,到把这些文件转换成使用者可以看、可以互动的网页的路径。

具体来说,这条路径包含以下不同的步骤:

  • 下载与解析 HTML,建构出 DOM
  • 下载与解析 CSS,建构出 CSSOM
  • 下载与解析 JavaScript,如有任何 JavaScript 会动到 DOM 或 CSSOM,则会执行 JavaScript 去改变 DOM 与 CSSOM
  • 根据 DOM 与 CSSOM 建构渲染树 (render tree)
  • 计算样式与布局 (layout)
  • 在记忆体中绘制 (paint) 像素
  • 将不同的图层合成 (composite)
  • 实际将像素绘制到画面上

如果要视觉化理解上面的路径,会是像下面这样

  HTML            CSS
    ↓              ↓
   DOM           CSSOM
    ↓              ↓
        ↘     ↙
      JavaScript

     Render Tree

       Style

       Layout

       Paint

     Composite

      Display

为什么要对这个路径有所掌握?

在理解完关键渲染路径的基本介绍,这时你可能会问,为什么身为前端开发者,我们会需要理解这个路径? 有什么好处?

身为前端工程师,效能优化是工作与面试时,经常需要面对到的议题。当谈到前端效能优化,有非常多不同的切入点可以讨论。

然而,如果想要有架构一点地讨论前端的效能优化,最推荐的方法之一,即是从路径的角度切入展开来讨论,这样就能把在路径中的每一个点,分别拉出来谈可以如何优化。

所以对关键渲染路径有所掌握,将能够让你更能有架构地分析前端、优化前端地效能。

DOM 与 CSSOM 的角色

关键渲染路径是从建构 DOM 与 CSSOM 开始,可以把 DOM 与 CSSOM 理解成 API,是透过转换成这个标准化的形式,让 JavaScript 可以去操作 DOM 与 CSSOM 上的元素。

以 DOM 来说,当 JavaScript 要去修改某个元素,或加事件监要去修改某个元素,都需要一个标准,让外部可以去操作与修改 HTML,而 DOM 即是提供这个标准,让 JavaScript 能够去操作与修改 HTML。

因此,HTML 被解析后会建构 DOM,而 JavaScript 透过修改 DOM 来去改内容。同样地,浏览器下载完、解析完 CSS 后,会生成 CSSOM,而 CSSOM 也可以理解成一个 API,让 JavaScript 能够去修改样式。

在初步理解完 DOM 与 CSSOM 后,我们就能进一步来讨论,可以如何优化这两个要件。

HTML 优化

要优化下载与解析 HTML,到 DOM 的建构这段,可以有几个思考点:

1. 让 HTML 变小

如果 HTML 文件越大,就要花越多时间下载与解析。因此,可以去思考使用者进到页面中,有什么部分是真正需要出现在首次渲染的画面中,只放真正需要的内容,让 HTML 尽可能变小,下载与解析起来就会快。

2. 如何让 DOM 尽可能最小化

常见的方式包含做分页 (pagination),比起一次就呈现很多页,导致要处理的元素很多,拆成多个页面,在需要时再加载,这样的效能会比较好。与此同时,可以透过虚拟化 (virtualization) 来让 DOM 变小。

先前有一个测试 (连结),同样是 10 万行的 DOM,渲染起来约要 242 毫秒,但如果用虚拟化的方式渲染,只需约 2.4 毫秒,这有相当大的差别。

3. HTML 用串流的方式传

因为 HTML 是可以被逐步解析 (incrementally parsed),所以可以不用一次传一整份,传完才解析,而是可以切成不同的小部分,然后串流的方式传到客户端,这样浏览器一接受到就可以直接开始解析,不用等整个 HTML 都下载完开始解析。

CSS 优化

接着来谈 CSS 部分的优化。在谈之前,有一个必须先谈的预设,就是浏览器会预设把 CSS 视为阻挡渲染的存在。意思是,当浏览器在解析 HTML 时,遇到会阻挡渲染的 CSS,就会停下来先处理 CSS,然后再回头解析 HTML。

之所以会阻挡渲染,是因为如果不阻挡,在 CSSOM 建构完后,又有新的样式变更,会让画面样式跳来跳去,这样使用体验很差。为了有良好的使用体验,在浏览器端才会设计成必须要等 CSSOM 建构完成才渲染。

在有了以上的观念后,可以透过以下手段来优化:

1. 把 CSS 放在文件最上方

CSS 要尽量放在最上方,这样才可以尽早下载、解析,然后形成 CSSOM;这段尽早完成就能尽早结束对渲染的影响。

2. 让 CSS 文件尽可能小

最小化 CSS (用 minimizer),以及把首屏不用的 CSS 移除掉,后面再加载就好。这么做就能及早让 CSS 被处理完,不会持续阻挡渲染。

3. 修改对首屏不重要的 CSS 的预设行为

前面浏览器预设 CSS 会阻挡渲染,但这点不是不能改变的。把对不重要的 CSS 改成不会阻挡渲染,也能让渲染更快完成。这点详细推荐 《The Simplest Way to Load CSS Asynchronously》 一文。

阅读更多

如果你对关键渲染路径这个主题感兴趣,我们在 E+ 有更完整讲解的版本,包含讨论为什么这条路径有「关键」称呼、JavaScript 在这条路径上扮演的角色、如何优化 JavaScript 对这条路径的影响、布局与绘制阶段的讨论与优化。有兴趣的读者,欢迎加入 E+ 成长计划。

本文为 E+ 成长计划的深度内容,截取段落开放免费阅读。欢迎加入 E+ 成长计划阅读完整版本 (点此了解 E+ 的详细介绍)

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們