# 前面的话

使用 Chrome DevTools 的 performance 面板可以记录和分析页面在运行时的所有活动。本文将详细介绍如何使用 performance 面板解决性能瓶颈

# 准备

# 【匿名模式】

匿名模式可以保证 Chrome 在一个相对干净的环境下运行。比如安装了许多 chrome 插件,这些插件可能会影响我们分析性能表现

使用快捷键 ctrl + shift + N 即可代码匿名模式下的 chrome 新标签页

# 【移动设备 CPU】

移动设备的 CPU 一般比台式机和笔记本弱很多。分析页面时,可以用 CPU 控制器(CPU Throttling)来模拟移动端设备 CPU

在 DevTools 中,点击 Performance 的 tab。 确保 Screenshots checkbox 被选中;点击 Capture Settings(⚙️)按钮,DevTools 会展示很多设置,来模拟各种状况;对于模拟 CPU,选择 4x slowdown,于是 Devtools 就开始模拟 4 倍低速 CPU

# 概览

# 【组成】

performance 面板有如下四个窗格:

1. controls。开始记录,停止记录和配置记录期间捕获的信息

2. overview。页面性能的高级汇总

3. 火焰图。 CPU 堆叠追踪的可视化

4. 统计汇总。以图表的形式汇总数据

# 【颜色表示】

HTML 文件为蓝色
脚本为黄色
样式表为紫色
媒体文件为绿色
其他资源为灰色

# 【做记录】

打开想要记录的页面,然后重新加载页面。 performance 面板会自动记录页面重新加载。

要记录页面交互,打开 performance 面板,然后按 Record 按钮 或者键入键盘快捷键 Cmd+E (Mac) 或 Ctrl+E (Windows / Linux),开始记录。记录时,Record 按钮会变成红色。执行页面交互,然后按 Record 按钮或再次键入键盘快捷键停止记录

完成记录后,DevTools 会猜测哪一部分记录最相关,并自动缩放到那一个部分

# 查看

# 【Overview】

Overview 窗格包含以下三个图表:

1. FPS。每秒帧数。绿色竖线越高,FPS 越高。 FPS 图表上的红色块表示长时间帧,很可能会出现卡顿

2. CPU。 CPU 资源。此面积图指示消耗 CPU 资源的事件类型

3. NET。每条彩色横杠表示一种资源。横杠越长,检索资源所需的时间越长。 每个横杠的浅色部分表示等待时间(从请求资源到第一个字节下载完成的时间)

可以放大显示一部分记录,以便简化分析。使用 Overview 窗格可以放大显示一部分记录。 放大后,火焰图会自动缩放以匹配同一部分

选择部分后,可以使用 W、A、S 和 D 键调整您的选择。 W 和 S 分别代表放大和缩小。 A 和 D 分别代表左移和右移

# 【火焰图】

火焰图上看到一到三条垂直的虚线。蓝线代表 DOMContentLoaded 事件。 绿线代表首次绘制的时间。 红线代表 load 事件

火焰图中选择事件时,Details 窗格会显示与事件相关的其他信息

# 诊断

# 【JS】

JavaScript 计算,特别是会触发大量视觉变化的计算会降低应用性能。 不要让时机不当或长时间运行的 JavaScript 影响用户交互

下面是一些常见 JavaScript 问题

1. 大开销输入处理程序影响响应或动画

让浏览器尽可能晚地处理触摸和滚动,或者绑定侦听

2. 时机不当的 JavaScript 影响响应、动画、加载

使用 requestAnimationFrame、使 DOM 操作遍布各个帧、使用网络工作线程

3. 长时间运行的 JavaScript 影响响应

将纯粹的计算工作转移到 web worker 中。如果需要 DOM 访问权限,配合使用 requestAnimationFrame

# 【样式】

样式更改开销较大,在这些更改会影响 DOM 中的多个元素时更是如此。 只要将样式应用到元素,浏览器就必须确定对所有相关元素的影响、重新计算布局并重新绘制

点击 Recalculate Style 事件(以紫色显示)可以在 Details 窗格中查看更多相关信息。 如果样式更改需要较长时间,对性能的影响会非常大。 如果样式计算会影响大量元素,则需要改进另一个方面

要降低 Recalculate Style 事件的影响,使用一些对渲染性能的影响较小的属性。如使用 transform 和 opacity 属性更改来实现动画,使用 will-change 或 translateZ 提升移动的元素

下面是一些常见的 CSS 问题

1. 大开销样式计算影响响应或动画

任何会更改元素几何形状的 CSS 属性,如宽度、高度或位置;浏览器必须检查所有其他元素并重做布局。避免会触发重排的 CSS 属性

2. 复杂的选择器影响响应或动画

嵌套选择器强制浏览器了解与所有其他元素有关的全部内容,包括父级和子级。尽量在 CSS 中引用只有一个类的元素

# 【重排】

布局(或重排)是浏览器用来计算页面上所有元素的位置和大小的过程。 网页的布局模式意味着一个元素可能影响其他元素;例如 body 元素的宽度一般会影响其子元素的宽度以及树中各处的节点等等。这个过程对于浏览器来说可能很复杂。 一般的经验法则是,如果在帧完成前从 DOM 请求返回几何值,将发现会出现 “强制同步布局”,在频繁地重复或针对较大的 DOM 树执行操作时这会成为性能的大瓶颈。

performance 面板可以确定页面何时会导致强制同步布局。 这些 Layout 事件使用红色竖线标记

“布局抖动” 是指反复出现强制同步布局情况。 这种情况会在 JavaScript 从 DOM 反复地写入和读取时出现,将会强制浏览器反复重新计算布局

# 【重绘】

绘制是填充像素的过程。这经常是渲染流程开销最大的部分。 如果在任何情况下注意到页面出现卡顿现象,很有可能存在绘制问题。

合成是将页面的已绘制部分放在一起以在屏幕上显示的过程。 大多数情况下,如果坚持仅合成器属性并避免一起绘制,性能会有极大的改进,但是需要留意过多的层计数

一定不要使用下面的代码

* {
  will-change: transform;
  transform: translateZ(0);
}

这是以迂回方式说想要提升页面上的每个元素。此处的问题是创建的每一层都需要内存和管理,而这些并不是免费的。事实上,在内存有限的设备上,对性能的影响可能远远超过创建层带来的任何好处。每一层的纹理都需要上传到 GPU,使 CPU 与 GPU 之间的带宽、GPU 上可用于纹理处理的内存都受到进一步限制

如果大部分渲染时间花费在绘制上,即表示存在绘制问题

下面是一些常见的绘制问题

1. 绘制风暴影响响应或动画

较大的绘制区域或大开销绘制影响了响应或动画,要避免绘制、提升将要移动到自有层的元素,使用变形和不透明度

2. 层数激增影响动画

使用 translateZ (0) 过度提升过多的元素会严重影响动画性能,要谨慎提升到层,并且仅在了解这样会有切实改进时才提升到层