Skip to content

8.2 检测性能问题

上一节通过深度剖析网络层面和渲染层面的工作原理,我们大致解决了以下几个问题:

  • 性能问题是什么?怎么出现的?
  • 性能优化是什么?
  • 性能优化应该怎么做?

从渲染流程的角度看性能优化,可以帮助我们了解原理,做到心中有数。然而性能问题出现的场景复杂,如果有一个工具可以协助我们检测问题,则会大大减少定位性能问题的时间。索性浏览器提供了这些工具,本节就来介绍如何检测性能问题。

8.2.1 主观感知性能

主观感知性能是用户对产品使用体验最直观的感知,很多时候我们不需要有非常明确的数据指标,关凭使用感受就能判断产品性能如何。

比如我们打开一个网页,页面加载了 5 秒钟还是白屏,此时你可能会直接关掉页面,因为毫无反馈的等待感觉非常糟糕。或者在一些列表页滚动、表单操作时,网页的响应速度比较慢,没有耐心的用户会连续不断地点击,结果页面反应变得更加卡顿,直接引起用户的反感。

因此,当用户主观感受到页面操作不流畅时,多半就是存在性能问题。但在这种情况除了立即着手解决性能问题,通常我们还有另一套方案 ——— 从用户体验入手,提升用户“感知到的性能”。这种方案在以下两种场景中可用:

  • 首页白屏:添加骨架屏或加载动画,甚至加一些趣味文字等,都可以增加用户的等待耐心。
  • 交互迟缓:如果产品交互反应比较慢,可以在第一次点击时加一个加载动画,防止用户频繁出发,导致更大面积的卡顿。

这两种方案虽然没有直接提升实际性能,但是从体验上来讲,拉高了用户的容忍度,这也属于主观感知性能方面的优化,往往这种方式非常重要。

8.2.2 性能面板检测

性能面板是在开发者工具中的一个标签页,主要作用就是检测当前页面的性能。使用无痕模式打开浏览器(无痕模式可保证 Chrome 在干净的状态下运行,不受浏览器扩展的影响),进入我们需要检测性能的网页,然后打开开发者工具,切换到性能检测面板,如图 9-2 所示:

从图中可以看出,性能面板由上下两个区域组成 ——— 上面是操作区域、下面是主体区域。主体区域默认是空的,中央有文字提示如何检测性能。提示信息向我们介绍了最常用的两个按钮,这两个按钮与操作区域的前两个按钮功能一样,分别是“圆点状”的录制按钮和“圆箭头状”的重新加载按钮。

这两个按钮都可以检测当前页面性能,但是适用场景不同,下面我们分别介绍。

重新加载按钮:检测首屏性能

点击重新加载按钮,当前页面会刷新,同时性能面板会分析加载性能。当页面加载完毕,性能面板会将将页面加载的分析结果展示,如图 9-3 所示:

看到图中密密麻麻的线条,很多同学直接被劝退了。别灰心,虽然看上去比较杂乱,但是详细了解每一块的作用之后,这个图看起来会非常直观。具体的图像内容分析我们稍后介绍,现在请看图中下半部分的“摘要”标签,这里是一个简单的环形图,展示了总加载耗时和渲染过程中各个阶段的耗时。

我们给它一个特写,如图 9-4 所示:

摘要部分最直观地展示了性能数据,通过这个部分,我们基本可以查看页面加载情况,可以根据这个数据做性能优化了。

录制按钮:检测交互性能

不同于重新加载按钮,录制按钮不会自动分析性能,他需要我们手动点击开始记录,手动点击结束记录,结束之后会分分析这个时间段我们操作页面的性能情况。

举个例子:假设我们要检测某个列表页的滚动性能,那么在滚动之前先点击开始记录,开始记录之后我们在页面操作滚动,操作完成后点击结束记录,这样我们操作这个页面点过程就会被记录下来,并且生成性能分析报告。

性能分析结果页与页面重载时的一致,这里不赘述了,我们依然可以在摘要标签下看到最终的数据结果。

性能分析图表

执行性能检测后会生成一分性能分析图表,这份图表乍一看很乱很难懂的样子,实际上它没有那么可怕。我们按照功能将图表从上到下分为三个部分,分别是概述部分、详情部分、统计部分。

(1)概述部分

概述部分以时间为横轴,分别展示了 CPU、网络在每个时间点的状态。其中“小山包”状的面积图表示 CPU 状态,高度越高表示 CPU 计算量越大;面积图下的蓝色线条表示网络,出现蓝色线条的部分表示该时间端有网络请求。

点击概述部分会出现两个托块,我们可以拖动托块来选择时间段。比如我要看 2s ~ 3s 这个区间的性能,就可以把左右托块分别放在 2s 和 3s 的位置,中间就是选中的时间段,这样详情部分就只会展示该时间段的性能数据。

(2)详情部分

在概述部分选中一个时间段(默认全部时间),详情部分会展示该时间段的详细性能数据。这些性能数据包含了网络、帧、CPU 等多个分类,我们抓主要矛盾,着重关注“主要”分类下的火焰图,它是详情部分中最重要的性能数据。

火焰图怎么看?其实也很简单:X 轴表示时间,Y 轴表示调用堆栈。火焰图默认是由多层的条状图形组成,上下层层叠加,当时间范围变大时它会成倍缩小,变成一个由秘密麻麻的条状块组成的不规则图形。事实上,火焰图包含的内容非常多,通过鼠标滚动将时间范围缩小(最小可缩至 1ms),火焰图会成倍放大,放大后可以清晰地看到条状图形的内容 ——— 它是一个函数,Y 轴从上到下堆叠的条状图形组成一个函数调用栈。

火焰图可以看到任意时间的函数调用情况,条形宽度代表函数执行消耗时间,火焰图可以帮助我们以最小粒度分析页面性能。

(3)统计部分

统计部分以饼图的形式展示了选中时间段的统计数据。不同于详情部分的超细粒度,统计部分只分析渲染过程中各个阶段的加载耗时,帮助我们快速定位是哪个阶段出了问题。统计的每个阶段其含义如下:

  • 正在加载:资源下载时间。
  • 正在执行脚本:脚本执行时间。
  • 渲染:页面渲染时间。
  • 绘制:页面绘制时间。
  • 系统:系统初始化时间。
  • 空闲:CPU 等待时间。

8.2.3 Lighthouse 检测

Lighthouse 是开发者工具中另一款检测性能的工具。使用该工具的步骤与性能面板一致,首先以无痕模式打开浏览器,进入目标网页,然后打开开发者工具并选中 Lighthouse 标签页,点击“分析网页加载情况”按钮,即可进入网页检测分析,如图 9-5 所示。

从图中可以看出,在进行网页分析之前,可以选择多个参数(模式、设备、类型),Lighthouse 会根据你选择的选项分析并生成相关报告。选项中的设备用于模拟设备环境,主要是 CPU 的差别;类别则表示要从网页的哪些方面进行分析,默认选择性能、最佳实践、SEO 三项即可。

模式是一组相对特别的选项,每种模式都有其独特的应用场景。Lighthouse 提供了三种模式选项:

  • 导航模式:分析单个页面加载。
  • 时间跨度模式:分析任意时间段,通常包含用户交互。
  • 快照模式:分析处于特定状态的页面。

与性能面板不同的是,Lighthouse 是针对整个页面分析,性能只是其中的一部分,它更懂优化网页需要解决什么问题。Lighthouse 不会列出晦涩难懂的专业数据(如 CPU 面积图、火焰图等)让开发者自己分析,它只会对我们关心的网页指标分析计算后打分,并直接告诉你怎么做可以提升分数,如图 9-6 所示。

这也是多数开发者的心声 ——— 不用给我看多么专业详细的数据,直接告诉我怎么办就得啦!Lighthouse 做到了这一点,它简化了网页分析和优化方案的产出,它的分析结果和优化建议能解决 80% 的问题。

按照分数划分,90 分以上属于优秀,表示没有大问题,80 以下的就要注意了,优化方案刻不容缓。点击某个网页指标可以看到该类型下的优化建议,根据建议逐条修复即可,非常简单。比如 SEO 的分析结果,它列出了怎么修改可以优化分数,如图 9-7 所示:

综合来说,Lighthouse 可以更快速更直接地分析网页各项指标并给出优化建议,适合大多数场景。如果在某些场景需要做到极致优化,那么清使用性能面板,从更细粒度的分析中一点点地抠出优化点。

8.2.4 构建性能检测

前端项目构建打包之后会生成静态资源文件,这些文件最终会部署到服务器上供用户访问。然而构建之后的文件也可能存在性能问题,比如某个文件体积过大,或打包了不需要的模块等,这些都需要我们在部署之前检测并处理。

多数情况下,打包后的静态资源已经将模块混淆压缩,生成纯粹的 JS 文件。当我们使用性能面板检测出某些问题时,可能很难确认问题的来源对应源码中的哪个模块。因此,对于打包构建的静态资源文件,除了可以使用性能面板检测“运行时”的性能,我们还应该在构建阶段检测“编译时”的性能。

检测“编译时”性能需要依赖构建工具实现。在 Webpack 或 Vite 中,都有可直接使用的、用于依赖分析的插件,可以分析项目中模块的引入情况和资源大小,从而帮助判断构建产物的性能。

以 Vite 为例,我们使用一个名为 rollup-plugin-visualizer 的插件,该插件会在构建之后生成一个 stats.html 文件,用浏览器打开该文件,可以看到页面如图 9-8 所示:

从图中可以清晰的看到构建后的代码包含哪些模块,哪个模块占用体积最大,模块的依赖情况如何。通过该图我们可以基本判断模块体积是否合理,是否有不需要的模块被打包,然后针对实际情况做相应的优化。