原文链接:Understanding the critical path, from web.dev。翻译时有删改。
关键渲染路径(critical rendering path)是指网页在正式开始渲染前所要经历的步骤。
前面在写《性能优化之 HTML 篇》 的时候,我们介绍的是如何将 HTML 发送到浏览器。而在本文,我们将要了解浏览器在下载 HTML 之后会做什么。
渐进式渲染
与桌面程序不同的是,网页是在访问时才派发下来的。一个网页中会包含很多资源,而这些资源不会一下全部下载下来,那么我们就要面临一个问题------浏览器什么时候开始渲染呢?
如果浏览器接收的只有一个 HTML,那么渲染会非常快。如果还额外包括一些 CSS 或 JavaScript,那么网页可能会先经历一个从无样式到有样式的转变,这种体验有时候比白屏还要糟糕。
了解关键渲染路径可以避免你阻止页面初始渲染,从而提升 Web 性能。当然,也不要为了尽快渲染,就把页面初始渲染时所必要的资源给删除了,也会影响最终的显示体验。
(关键)渲染路径
在浏览器真正开始渲染之前,会经历以下几个步骤:
- 从 HTML 构建 DOM(Document Object Model)
- 从 CSS 构建 CSSOM(CSS Object Model)
- 执行涉及 DOM 或 CSSOM 修改的 JavaScript 代码
- 使用 DOM 和 CSSOM 构建渲染树(Render Tree)
- 执行样式(Style)和布局(Layout)操作,确定元素在网页中位置
- 绘制(Paint)元素像素到内存中
- 对生成的元素像素进行合成(Composite)
- 将最终生成的像素绘制到屏幕上
完成这些步骤后,用户才能看到内容。
当然,这个渲染过程会在整个页面周期内会多次发生,只不过有时候只会涉及上述的部分步骤。关键渲染路径聚焦于上面所述的初始渲染过程、并依赖于渲染所需的关键资源。
关键渲染路径上有哪些资源?
浏览器为了完成初始渲染,需要等待一些额外的关键资源下载。这些资源包括:
- 一部分 HTML
<head>
中阻塞渲染(Render-blocking)的 CSS<head>
中阻塞渲染的 JavaScript
这里值得注意的是,浏览器是以流式处理 HTML 的。一旦接收到了部分 HTML,浏览器就开始处理了。同时,浏览器会在接收其余部分的页面 HTML 之前,尽可能把已解析的部分进行很好渲染。
也就是说,在初始渲染阶段,浏览器不会等待以下资源:
- 所有 HTML
- 字体
- 图片
<head>
元素外非阻塞渲染的 JavaScript(例如:放在 HTML 末尾的<script>
元素)<head>
元素外非阻塞渲染的 CSS,或者是不适应于当前视口的media
attribute 的 CSS
字体和图片通常被浏览器看作是后续页面重新渲染期间要填充的内容,因此初始渲染时就不予考虑了。不过,这也可能会造成初始渲染时页面出现空白,甚至是布局变化。
<head>
元素是处理关键渲染路径的关键,其中主要包含网页的一些元数据,而用户看到的内容则是放在 <body>
中。在浏览器渲染内容前,既需要知道要渲染的内容,也需要知道有关如何呈现内容的元数据。
不过,不是所有 <head>
中的内容都会影响页面初始渲染。要理解这一点,需要先知道阻塞渲染的 CSS 和阻塞解析的 JavaScript 的概念。
阻塞渲染的资源
有些资源会被认为非常重要,以至于浏览器在遇到他们时会暂停页面渲染,直到处理完它们。CSS 默认就属于这一类资源。
当浏览器遇到 CSS(不管是 <style>
元素的内联样式,还是由 <link rel="stylesheet">
制定的外部样式资源),就会停止渲染操作,直到下载并处理完 CSS,才会继续。
当然阻止渲染并不是说浏览器不会再执行其他操作了。在暂停渲染和处理 CSS 资源时的这个阶段,浏览器会继续处理其余的 HTML 和其他要做的工作。
Chrome 105 中添加了 blocking="render" 属性的支持,允许开发者显式标记 <link>
、<script>
或 <style>
这些元素是阻塞渲染的,而这类阻塞不会组织浏览器继续解析余下的文档。
阻塞解析的资源
当浏览器在遇到这类阻塞解析的资源时,会暂停 HTML 的解析。JavaScript 默认就属于这一类资源(除非特意指定是异步(async)或延迟(defer)的)。
阻塞了解析,实际上也就阻塞了渲染。因为浏览器无法在解析完当前的 JavaScript 代码之前继续前进,因此也就无法访问后面的内容。
阻塞解析不仅仅会阻止渲染,也可能会产生巨大的性能成本。不过浏览器在主解析器(primary parser)之外,还额外提供了一种称之为预加载扫描器(preload scanner)的辅助 HTML 解析器( secondary HTML parser)协同使用------它可以帮助你提前下载未来要用的资源。
识别阻塞资源
许多性能审核工具可以识别渲染和解析器阻塞资源。 WebPageTest 在资源 URL 左侧用橙色圆圈标记渲染阻塞资源:
在页面开始渲染之前,需要下载并处理的所有阻塞资源,在瀑布流中使用深绿色实线表示。
Lighthouse 还以更巧妙的方式突出显示阻塞渲染的资源,只有当这个资源会实际延迟页面渲染时才突出显示。这既能避免误报,也能最大限度地减少渲染阻塞。下面是使用 Lighthouse 运行与前面 WebPageTest 相同 URL 时的结果。Lighthouse 将其中一个样式表文件识别为阻塞渲染的资源。
优化关键路径
优化关键渲染路径涉及减少接收 HTML 的时间(由 TTFB 指标表示),并尽可能减少会阻塞渲染的资源的影响。
关键内容渲染路径
长期以来,关键渲染路径一直关注的是页面初始渲染。然而,随着更多以用户为中心的 Web 性能指标出现,也引起了一些质疑:关键渲染路径的测算终点应该是首次绘制(very first paint),还是随后的一个更加内容丰富的绘制?
有一种观点是专注于最大内容绘制(Largest Contentful Paint,简称 LCP)甚至首次内容绘制(First Contentful Paint,FCP)之前的这段时间,把这作为内容渲染路径的一部分。在这种情况下,你可能需要包含一些资源,这些资源不一定导致阻塞,但却是呈现内容丰富的绘画所必需的。
无论你对"关键(critical)"的确切定义是什么,了解什么会阻碍任何初始渲染和关键内容渲染都很重要。而不管是首次绘制还是内容绘制,都是能带用户带来价值的。
识别内容渲染路径
许多工具可以识别 LCP 元素 及其渲染时间。除了 LCP 元素之外,Lighthouse 还将帮助识别 LCP 阶段 以及每个阶段所花费的时间,帮助你了解如何去优化及最佳实践。
对于更复杂的站点,Lighthouse 还在单独的审核(audit)中突出显示了关键请求链:
此 Lighthouse 审核会观察以高优先级加载的所有资源,包括 Chrome 默认设置为高优先级资源的 Web 字体和其他内容,即使它实际上并不阻塞渲染。
总结
请问我们带大家了解了什么是关键渲染路径,简单点说关键渲染路径就是指在页面初始渲染时所需要的最小资源量。
在初始渲染中,所涉及的资源量越少,渲染就越快,否则就越慢。
默认情况下,浏览器不必等到所有 HTML 到达,即可开始渲染。同时还要明白,哪些资源会导致渲染阻塞。比如 <head>
中的 CSS 会阻塞渲染,而 JavaScript 则会阻塞解析。
当然关于如何做好 <head>
中元素的优化工作,还有很多内容可以讲。更多关于性能改进的知识,我们会在下一节中详细描述,敬请期待。
感谢你的阅读,再见。