前端性能优化学习 02 Web 性能指标

Web 性能指标

我们已经知道性能的重要性,但当我们讨论性能的时候,让一个网页变得更快,具体指哪些内容?

事实上性能是相对的:

  • 对于一个用户而言,一个站点可能速度很快(在具有功能强大的设备的快速网络上),而对于另一个用户而言,一个站点可能会较慢(在具有低端设备的慢速网络上)。
  • 两个站点可能会在完全相同的时间内加载,但一个站点似乎加载速度会更快(如果它逐步加载内容,而不是等到最后显示所有内容)。
  • 一个网站可能加载很快,但在后来的用户交互会很慢。

所以在讨论性能的时候,精确的、可量化的指标很重要。

但是,一个度量标准是基于客观标准并且可以定量地度量的,所以一个指标的好坏并不一定意味着是有用的。

对于 Web 开发人员来说,如何衡量一个 Web 页面的性能一直都是一个难题。

最初,我们使用 TTFB (Time to First Byte)、DomContentLoaded 和 Load 这些衡量文档加载进度的指标,但它们不能直接反应用户视觉体验。

为了能衡量用户视觉体验,Web 标准中定义了一些性能指标,这些性能指标被各大浏览器标准化实现,例如 First paint(首次绘制)和 First contentful paint(首次内容绘制)。还有一些由 Web 孵化器社区组(WICG)提出的性能指标,如 Largest Contentful Paint(最大内容绘制)、Time to interactive(可持续交互时间)、First input delay(首次输入延迟)、First CPU idle(首次 CPU 闲置)。另外还有 Google 提出的 First Meaningful Paint(首次有意义的绘制)、Speed index(速度指数),百度提出的 First Screen Paint(首屏可视时间)。

这些指标之间并不是毫无关联,而是在以用户为中心的目标中不断演进出来的,有的已经不再建议使用,有的被各种测试工具实现,有的则可以作为通用标准,有各大浏览器提供的可用于在生产环境测量的 API。

下面主要通过三个层面进行介绍:

  • RAIL 性能模型 - 从用户体验的角度给定的体验标准(Response、Animation、Idle、Load)
  • 基于用户体验的核心指标 - 基于 RAIL 下具体的指标方案
  • 新一代型性能指标:Web Vitals - 在以上指标方案的简化,重点 LCP(Largest Contentful Paint)、FID(First input delay)、CLS(Cumulative Layout Shift)。

RAIL 性能模型

RAIL 是 ResponseAnimationIdleLoad 的首字母缩写,是一种由 Google Chrome 团队于 2015 年提出的性能模型,用于提升浏览器内的用户体验和性能。

RAIL 模型的理念是“以用户为中心,最终目标不是让您的网站在任何特定设备上都能运行很快,而是使用户满意”。

前端性能优化学习 02 Web 性能指标_第1张图片

RAIL 名字的由来是四个英文单词的首字母:

  • 响应(Response):应该尽可能快速的响应用户,应该在 100ms 以内响应用户输入。
    • 所谓的响应并不是返回结果,而是给出用户可以感知的状态交互。
  • 动画(Animation):在展示动画的时候,每一帧应该以 16ms 进行渲染,这样可以保持动画效果的一致性,并且避免卡顿。
    • 差不多每秒 60 桢
  • 空闲(Idle):当使用 JavaScript 主线程的时候,应该把任务划分到执行时间小于 50ms 的片段中去,这样可以释放线程以进行用户交互。
    • JS 中将超过 50ms 的执行任务称为**“长任务”**,由于长任务在执行过程中没有办法响应用户交互,所以要尽量避免
  • 加载(Load):应该在小于 1s 的时间内加载完成你的网站,并可以进行用户交互。

根据网络条件和硬件的不同,用户对性能延迟的理解也有所不同。

1s 是基于性能比较好的 PC 电脑以及良好的网络环境所得到的指标,用户对此已经习以为常。

而在 3G 连接速度较慢的移动设备上加载网络需要花费更多时间,因此移动用户通常更耐心,在移动设备上加载 5s 是一个更现实的目标。

这四个单词代表与网站或应用的生命周期相关的四个方面,这些方面会以不同的方式影响整个网站的性能。

用户对于延迟的感知

我们将用户作为之后性能优化的中心,首先需要了解用户对于延迟的反应。

用户感知延迟的时间,如下表所示:

延迟 用户感知
0 ~ 16ms 人眼可以感知每秒 60 桢的动画,即每帧 16ms,除了浏览器将一帧画面会绘制到屏幕上的时间,网站应用大约需要 10ms 来生成一桢
0 ~ 100ms 在该时间范围内响应用户操作,才会是流畅的体验
100 ~ 1000ms 能够感觉到明显的延迟
> 1s 用户的注意力将离开对执行任务的关注
> 10s 用户感到失望,可能会放弃任务

响应 Response

指标:应该尽可能快速的响应用户,应该在 100ms 以内响应用户输入。

网站性能对于响应方面的要求是,在用户感知延迟之前接收到操作的反馈。比如用户进行了文本输入、按钮点击、表单切换以及启动动画等操作后,必须在 100ms 内收到反馈,如果超过 100ms 的时间,用户就会感知延迟。

看似很基本的用户操作背后,可能会隐藏着复杂的业务逻辑处理以及网络请求与数据计算。对此我们应当谨慎,将较大开销的工作放在后台异步执行,而即便后台要处理数百毫秒才能完成的操作,也应当给用户提供及时的阶段性反馈。

比如点击按钮向后台发起某项业务处理请求时,首先反馈给用户开始处理的提示,然后在处理完成的回调中反馈完成的提示。

动画 Animation

指标:在展示动画的时候,每一帧应该以 10ms 进行渲染,这样可以保持动画效果的一致性,并且避免卡顿。

前端所涉及的动画不仅有炫酷的 UI 特效,还包括滚动和触摸、拖动等交互效果,而这一方面的性能要求就是流畅。众所周知,人眼具有视觉暂留特性,就是光对视网膜所产生的视觉,在光停止作用后,仍能保留一段时间。

研究表明这是由于视神经存在反应速度造成的,其值是 1/24s,即当我们所见的物体移除后,该物体在我们眼中并不会立即消失,而会延续存在 1/24s 的时间。对动画来说,无论动画帧率由多高,最后我们仅能分辨其中的 30 桢,但越高的帧率会带来更好的流畅体验,因此动画要尽力达到 60fps 的帧率。

目前大多数设备的屏幕刷新率为 60次/秒,那么浏览器渲染动画或页面的每一帧的速率也需要跟设备屏幕的刷新率保持一致。所以根据 60fps 帧率的计算,每一帧画面的生成都需要经过若干步骤,一桢图像的生成预算为 16ms(1000ms / 60 ≈ 16.66ms),除去浏览器绘制新桢的时间,留给执行代码的时间仅 10ms 左右。如果无法符合此预算,帧率将下降,并且内容会在屏幕上抖动。此现象通常称为卡顿,会对用户体验产生负面影响。

可以打开 chrome 提供的示例页面查看效果,一直点击 add 10,直到蓝色方块的移送速度明显变慢:Janky Animation

空闲 Idle

指标:当使用 JavaScript 主线程的时候,应该把任务划分到执行时间小于 50ms 的片段中去,这样可以释放线程以进行用户交互。

要使网站响应迅速、动画流畅,通常需要较长的处理时间,但以用户为中心来看待性能问题,就会发现并非所有工作都需要在响应和加载阶段完成,我们完全可以利用浏览器的空闲时间处理可延迟的任务,只要让用户感受不到延迟即可。利用空闲时间处理延迟,可减少预加载的数据大小,以保证网站或应用快速完成加载。

为了更加合理的利用浏览器的空闲时间,最好将处理任务按 50ms 为单位分组。这么做就是保证用户在发生操作后的 100ms 内给出响应。

加载 Load

指标:首次加载应该在小于 5s 的时间内加载完成,并可以进行用户交互。对于后续加载,则是建议在 2s 内完成。

用户感知要求我们尽量在 5s 内完成页面加载,如果没有完成,用户的注意力就会分散到其他事情上,并对当前处理的任务产生中断感。需要注意的是,这里在 5s 内完成加载并渲染出页面的要求,并非要完成所有页面资源的加载,从用户感知体验的角度来说,只要关键渲染路径完成,用户就会认为全部加载已完成。

对于其他非关键资源的加载,延迟到浏览器空闲时段再进行,是比较常见的渐进式优化策略。比如图片懒加载、代码拆分等优化手段。

基于用户体验的性能指标

基于用户体验的核心指标 是 Google 在 web.dev 提出的。

First Contentful Paint(FCP)

FCP(First Contentful Paint)首次内容绘制,浏览器首次绘制来自 DOM 内容的时间,内容必须是文本、图片(包含背景图)、非白色的 canvas 或 SVG,也包括带有正在加载中的 Web 字体的文本。

前端性能优化学习 02 Web 性能指标_第2张图片

这是用户第一次开始看到页面内容,但仅仅有内容,并不意味着它是有用的内容(例如 Header、导航栏等),也不意味着用户要消费的内容。

速度指标

FCP 时间(以秒为单位) 颜色编码 FCP 分数(HTTP 存档百分位数)
0-2 绿色(快速) 75-100
2-4 橙色(中等) 50-74
>4 红色(慢) 0-49

优化方案

https://web.dev/fcp/#how-to-improve-fcp

Largest Contentful Paint(LCP)

LCP(Largest Contentful Paint)最大内容绘制,可视区域中最大的内容元素呈现到屏幕上的时间,用以估算页面的主要内容对用户可见时间。

LCP 考虑的元素:

  • 元素
  • 元素内的 元素
  • 元素(封面图)
  • 通过 url() 函数加载背景图片的元素
  • 包含文本节点或其他内联级文本元素子级的块级元素

为了提供良好的用户体验,网站应力争使用 2.5 秒或更短的“最大内容绘制”。为确保您达到大多数用户的这一目标,衡量移动设备和台式机设备的页面加载量的第 75 个百分位数是一个很好的衡量标准。

以下是一些示例:

前端性能优化学习 02 Web 性能指标_第3张图片

前端性能优化学习 02 Web 性能指标_第4张图片

在以上两个时间轴中,最大的元素随内容加载而变化。在第一个示例中,新内容被添加到 DOM 中,并且更改了最大的元素。在第二个示例中,布局发生更改,以前最大的内容从视口中删除。

通常情况下,延迟加载的内容要比页面上已有的内容大,但不一定是这种情况。接下来的两个示例显示了在页面完全加载之前发生的最大内容绘制。

前端性能优化学习 02 Web 性能指标_第5张图片
前端性能优化学习 02 Web 性能指标_第6张图片

在第一个示例中,Instagram 徽标相对较早的加载,即使逐渐显示其他内容,它仍然是最大的元素。在第二个示例 Google 搜索结果页面示例中,最大的元素是一段文本,该文本在任何图像或徽标加载完成之前显示。由于所有单个图像均小于此段,因此在整个加载过程中,它始终是最大的元素。

在 Instagram 时间轴的第一帧中,您可能会注意到相机徽标没有被当作最大元素(周围没有绿色框)。那是因为它是一个 元素,并且 元素当前不被视为 LCP 候选对象。

速度指标

LCP 时间(以秒为单位) 颜色编码
0-2.5 绿色(快速)
2.5-4 橙色(中等)
>4 红色(慢)

优化方案

https://web.dev/optimize-lcp/

First Input Delay(FID)

FID(First Input Delay)首次输入延迟,从用户第一次与页面交互(例如点击链接、点击按钮等)到浏览器实际能够响应该交互的时间。

输入延迟是因为浏览器的主线程正忙于其他事情,所以不能响应用户。发生这种情况的一个常见原因是浏览器正忙于解析和执行应用程序加载的大量计算的 JavaScript。

首次输入延迟通常发生在第一次内容绘制(FCP)和可持续交互时间(TTI)之间,因为页面已经呈现了一些内容,但还不能可靠地交互。

前端性能优化学习 02 Web 性能指标_第7张图片

如上图所示,浏览器接收到用户输入操作时,主线程正忙于执行一个耗时比较长的任务,只有当这个任务执行完成后,浏览器才能响应用户的输入操作。它必须等待的时间就是此页面上该用户的 FID 值。

例如,以下所有 HTML 元素都需要在响应用户交互之前等待主线程上正在进行的任务完成:

  • 文本输入框,复选框和单选按钮(