渲染性能

如果网站和应用运行不佳,用户就会注意到,因此优化渲染性能至关重要!

Paul Lewis

当今的网络用户希望他们访问的网页是交互式且流畅的,这正是您需要投入越来越多的时间和精力。网页不仅要快速加载,还要在整个生命周期内快速响应用户输入。实际上,这方面的用户体验正是 Interaction to Next Paint (INP) 指标所衡量的。良好的 INP 意味着网页能够始终如一地可靠地响应用户的需求。

虽然让网页看起来简洁明快的一个主要组成部分是您为响应用户互动而执行的 JavaScript 数量,但用户期待的是界面的视觉变化。界面的视觉变化是多种工作类型的结果,通常统称为渲染,这项工作需要尽快完成,才能让用户感觉快速而可靠。

若要编写可快速响应用户互动的网页,您需要了解浏览器如何处理 HTML、JavaScript 和 CSS,并确保您编写的代码(以及您添加的任何其他第三方代码)尽可能高效地运行。

关于设备刷新频率的注意事项

一名用户正在用手机与网站互动。
在构建能够快速响应用户输入的网站时,显示屏的刷新率是一项重要的考虑因素。

目前,大多数设备的屏幕刷新率为每秒 60 次。每次刷新都会生成您看到的视觉输出,通常称为“帧”。以下视频中演示了帧的概念:

Chrome 开发者工具的性能面板中显示的帧。当光标在顶部附近的幻灯影片上滑动时,提示中会显示每一帧的放大表示,因为移动设备导航菜单会以动画形式切换到其“打开”状态。

虽然设备的屏幕始终以一致的速率刷新,但在设备上运行的应用不一定总能生成足够的帧来匹配该刷新率。例如,如果有正在播放的动画或过渡效果,浏览器需要匹配设备的刷新频率,才能为每次屏幕刷新生成一帧。

鉴于典型的显示屏每秒刷新 60 次,一些简单的数学运算结果显示浏览器有 16.66 毫秒的时间来生成每一帧。但实际上,浏览器对于每一帧都有自己的开销,因此您的所有工作都需要在 10 毫秒内完成。如果无法达到此预算,帧速率会下降,并且网页内容会在屏幕上发生抖动。这种现象通常称为“卡顿”。

但是,您的目标会根据您尝试执行的工作类型而发生变化。达到 10 毫秒的阈值对于动画至关重要,动画会在两点之间的一系列帧中插入屏幕上的对象。当涉及到界面中的离散更改(即从一个状态进入另一个状态,且中间没有任何动作时),建议您在能即时给用户感受到的时间范围内实现此类更改。在此类情况下,经常提到 100 毫秒,但 INP 指标的“良好”阈值为 200 毫秒或更低,以便适应更多具有不同功能的设备。

无论您的目标是什么,无论是生成动画为避免卡顿而需要呈现的多帧,还是仅仅是尽快在界面中产生离散的视觉变化,了解浏览器的像素管道的工作原理都对您的工作至关重要。

像素管道

作为 Web 开发者,您需要了解并注意以下五个主要方面。这五个区域是您拥有最大控制权的区域,每个区域都代表像素到屏幕管道中的一个关键点:

完整的像素管道,包含五个步骤:JavaScript、样式、布局、绘制和合成。
完整的像素管道,如图所示。
  • JavaScript:JavaScript 通常用于处理会使界面发生视觉变化的工作。例如,这可能是 jQuery 的 animate 函数、对数据集进行排序或向页面添加 DOM 元素。不过,JavaScript 并不是触发视觉变化的绝对必要条件:CSS 动画CSS 过渡Web Animations API 能够为网页内容添加动画效果。
  • 样式计算:根据匹配的选择器,计算出哪些 CSS 规则应用于哪些 HTML 元素的过程。例如,.headline 就是这样一个 CSS 选择器示例,它适用于任何具有 class 属性值且包含 headline 类的 HTML 元素。因此,已知规则后,系统就会应用这些规则,并计算每个元素的最终样式。
  • 布局:一旦浏览器知道对某个元素应用了哪些规则,它就可以开始计算页面的几何图形,例如元素占据了多少空间以及元素在屏幕上的显示位置。在 Web 的布局模型中,一个元素可能会影响其他元素。例如,<body> 元素的宽度通常会影响其子元素在树中各下层的尺寸,因此对浏览器来说,这个过程可能会相当复杂。
  • 绘制:绘制是填充像素的过程。它涉及到在计算完元素在网页上的布局后绘制文本、颜色、图片、边框、阴影,基本上还包括元素的每个视觉方面。绘制通常在多个表面(通常称为图层)上完成。
  • Composite:由于网页的某些部分可能会绘制到多个图层上,因此它们需要以正确的顺序应用到屏幕上,才能使网页按预期呈现。这对于与其他元素重叠的元素尤为重要,因为错误可能会导致一个元素错误地显示在另一个元素之上。

像素管道的每一个部分都可能造成动画出现卡顿,或延迟帧的绘制(即使界面出现离散的视觉更改)。因此,请务必确切了解代码会触发流水线的哪些部分,并调查是否可以将更改限制为仅在像素流水线中渲染所需的部分。

您可能听说过与“绘制”结合使用的“光栅化”一词。这是因为绘制实际上分为两个任务:

  1. 创建绘制调用列表。
  2. 填充像素。

后者称为“光栅化”,因此每当您在开发者工具中看到绘制记录时,都应将其视为包含光栅化。在某些架构中,绘制调用列表和光栅化的创建是在不同的线程上完成的,但作为开发者,您无法控制这一点。

您不一定总是在每一帧中都会处理流水线的每个部分。实际上,当您进行视觉更改时,流水线通常会以三种方式(使用 JavaScript、CSS 或 Web Animations API)针对给定帧运行三种方法。

1. JS / CSS > 样式 > 布局 > 绘制 > 合成

完整的像素管道,未遗漏任何步骤。

如果您更改“布局”属性,例如会更改元素几何图形(例如宽度、高度或其位置)的属性(例如 lefttop CSS 属性),则浏览器需要检查所有其他元素并“自动重排”网页。任何受影响的区域都需要重新绘制,并且最终绘制的元素需要重新合成。

2. JS / CSS > 样式 > 绘制 > 合成

省略了布局步骤的像素管道。

如果您更改了 CSS 中某个元素的“仅绘制”属性(例如 background-imagecolorbox-shadow 等属性),则无需设置布局步骤,即可提交对页面的视觉更新。如果可能的话,您可以省略布局步骤,从而避免开销高昂的布局工作,否则可能会导致在生成下一帧时显著延迟。

3. JS / CSS > 样式 > 合成

省略了布局和绘制步骤的像素管道。

如果您更改既不需要布局也不需要绘制的属性,浏览器可以直接跳到合成步骤。对于网页生命周期中的高压力点(例如动画或滚动),这是最便宜且最理想的途径。趣味小知识:Chromium 会优化页面的滚动,以便尽可能仅在合成器线程上发生,这意味着即使页面没有响应,您仍然可以滚动页面,查看之前绘制到屏幕上的部分。

Web 性能是一种避免工作的艺术,同时尽可能地提高任何必要工作的效率。很多情况下,这需要与浏览器配合,而不是跟它对着干。值得注意的是,流水线中之前显示的工作在计算开销方面有所不同;一些任务本身比其他任务更昂贵!

我们来深入了解一下流水线的不同部分。下面将介绍一些常见问题,以及如何诊断和修复这些问题。

浏览器渲染优化

Udacity 课程屏幕截图

性能对用户而言至关重要,为了打造良好的用户体验,Web 开发者需要构建能够快速响应用户互动并流畅呈现的网站。性能专家 Paul Lewis 可随时帮助您消除卡顿,并打造能够保持每秒 60 帧性能的 Web 应用。在本课程中,您将学习分析应用性能所需的工具,并确定渲染性能不佳的原因。此外,您还将探索浏览器的渲染管道,并探索有助于更轻松地构建速度快且用户感觉愉悦的网站的模式。

这是 Udacity 提供的免费课程,您可以随时学习