关键渲染路径及度量转载
优化关键渲染路径是指优先显示与当前用户操作有关的内容。
要提供快速的网络体验,浏览器需要做许多工作。这类工作大多数是我们这些网络开发者看不到的: 我们编写标记,屏幕上就会显示出漂亮的页面。
但浏览器到底是如何使用我们的 HTML、CSS 和 JavaScript 在屏幕上渲染像素的呢?
从收到 HTML、CSS 和 JavaScript 字节到对其进行必需的处理,从而将它们转变成渲染的像素这一过程中有一些中间步骤,优化性能其实就是了解这些步骤中发生了什么 - 即关键渲染路径。
通过优化关键渲染路径,我们可以显著缩短首次渲染页面的时间。 此外,了解关键渲染路径还可以为构建高性能交互式应用打下基础。
处理交互式更新的过程是相同的,只是在连续循环中完成,理想情况下每秒可以处理 60 帧!
度量
作为每个可靠性能策略的基础,准确的评估和检测必不可少。 无法评估就谈不上优化。本文说明了评估 CRP 性能的不同方法。
- Lighthouse 方法会对页面运行一系列自动化测试,然后生成关于页面的 CRP 性能的报告。 这一方法对您的浏览器中加载的特定页面的 CRP 性能提供了快速且简单的高级概览,让您可以快速地测试、循环访问和提高其性能。
- Navigation Timing API 方法会捕获真实用户监控 (RUM) 指标。如名称所示,这些指标捕获自真实用户与网站的互动,并为真实的 CRP 性能(您的用户在各种设备和网络状况下的体验)提供了准确的信息。
通常情况下,最好利用 Lighthouse 发现明显的 CRP 优化机会,然后使用 Navigation Timing API 设置您的代码,以便监控应用在实际使用过程中的性能。
使用 Lighthouse 审核页面
Lighthouse 中看到页面的 CRP 结果将如以下屏幕截图所示。
使用 Navigation Timing API 设置您的代码
结合使用 Navigation Timing API 和页面加载时发出的其他浏览器事件,您可以捕获并记录任何页面的真实 CRP 性能。
上图中的每一个标签都对应着浏览器为其加载的每个网页追踪的细粒度时间戳。实际上,在这个具体例子中,我们展示的只是各种不同时间戳的一部分。我们暂且跳过所有与网络有关的时间戳,但在后面的课程中还会做详细介绍。
那么,这些时间戳有什么含义呢?
domLoading
: 这是整个过程的起始时间戳,浏览器即将开始解析第一批收到的 HTML 文档字节。domInteractive
: 表示浏览器完成对所有 HTML 的解析并且 DOM 构建完成的时间点。domContentLoaded
: 表示 DOM 准备就绪并且没有样式表阻止 JavaScript 执行的时间点,这意味着现在我们可以构建渲染树了。- 许多 JavaScript 框架都会等待此事件发生后,才开始执行它们自己的逻辑。因此,浏览器会捕获
EventStart
和EventEnd
时间戳,让我们能够追踪执行所花费的时间。
- 许多 JavaScript 框架都会等待此事件发生后,才开始执行它们自己的逻辑。因此,浏览器会捕获
domComplete
: 顾名思义,所有处理完成,并且网页上的所有资源(图像等)都已下载完毕,也就是说,加载转环已停止旋转。loadEvent
: 作为每个网页加载的最后一步,浏览器会触发on load
事件,以便触发额外的应用逻辑。
HTML 规范中规定了每个事件的具体条件: 应在何时触发、应满足什么条件等等。对我们而言,我们将重点放在与关键渲染路径有关的几个关键里程碑上:
domInteractive
表示 DOM 准备就绪的时间点。domContentLoaded
一般表示 DOM 和 CSSOM 均准备就绪的时间点。- 如果没有阻塞解析器的 JavaScript,则
DOMContentLoaded
将在domInteractive
后立即触发。
- 如果没有阻塞解析器的 JavaScript,则
domComplete
表示网页及其所有子资源都准备就绪的时间点。
<!DOCTYPE html>
<html>
<head>
<title>Critical Path: Measure</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<script>
function measureCRP() {
var t = window.performance.timing,
interactive = t.domInteractive - t.domLoading,
dcl = t.domContentLoadedEventStart - t.domLoading,
complete = t.domComplete - t.domLoading;
var stats = document.createElement('p');
stats.textContent = 'interactive: ' + interactive + 'ms, ' +
'dcl: ' + dcl + 'ms, complete: ' + complete + 'ms';
document.body.appendChild(stats);
}
</script>
</head>
<body on load="measureCRP()">
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
</body>
</html>
上面的例子乍一看可能有点晕,但实际上的确相当简单。Navigation Timing API 捕获所有相关时间戳,而我们的代码只是等待 on load
事件触发 - 回想一下,on load
事件在domInteractive
、domContentLoaded
和 domComplete
之后触发 - 然后计算各个时间戳之间的间隔。
完成了所有该做的工作,我们现在知道了需要追踪哪些具体的里程碑,以及用于输出这些评估的简单功能。请注意,除了将这些评估结果显示在网页上,您还可以修改代码,将这些评估结果发送到分析服务器上(Google Analytics(分析)会自动完成这项工作),这是一种监控网页性能的好方法,可以借此找出哪些网页还需要作出进一步优化。
DevTools 怎么样呢?
尽管本文档使用 Chrome DevTools 的 Network 面板说明 CRP 概念,DevTools 当前并不非常适合 CRP 评估,因为它没有隔离关键资源的内置机制。运行 Lighthouse 审核来帮助识别此类资源。