logo

鱼肚的博客

Don't Repeat Yourself

前端性能优化之读懂Performance

在做优化的时候,最重要的事情就是找到瓶颈点。因为优化后的收益,取决于优化部分占用的性能比例 * 优化比例。在相同的优化比较下,找到占比最大的瓶颈,能更快地实现优化的效果。

在前端领域中,有一项非常重要的性能衡量工具,即Chrome Devtools中的"Performance"标签页。但是怎么去读懂这个页签下的数据呢?网上这部分的资料并不太多,这里我介绍下使用"Performance"标签页时的一些心得体会,希望能帮助到读者。

基本的用法

打开Chrome浏览器的检查工具,切换到Performance页签,可以看到如下的页面:

image-20201222164844833

在左上角有三个控制按钮,依次是 "Record/Stop"、"Reload"和"Clear"。

选择任意想要测试的过程,点击"Record",并在测量结束之后,点击"Stop"。之后Chrome就会自动解析这段时间内抓取的数据,并生成报告。

为避免Chrome卡死,记录的时间最好不要太长。

“Reload”按钮适合于测量首页打开性能,它会自动刷新整个页面,并开始记录性能。"Clear"按钮则可以用于清除上次测量的数据。

在抓取数据完成后,一般会生成一个类似这样的报告出来。

image-20201222164956174

为了更好地读取信息,最好采用development版本的前端资源,方便查看Source Map。

读懂报告

概览

首先要读懂报告中的概览信息。

在左下角展示出的饼图中,有各个阶段的名称、占用时间、颜色信息。

image-20201222165029330

这里一般来说,需要着重关注的有两个:一是黄色的区域,代表脚本执行时间,另一个是紫色的渲染时间。

Bottom-Up

在"Summary"的右侧,有一个"Bottom-Up"的页签,它的里面可以按照排序查看各个阶段占用的时间。

image-20201222165111861

这里有两列时间数据,一是"Self Time"代表任务自身执行所消耗的时间,二是"Total Time"代表此任务及其调用的附属子任务一共消耗的时间。这两列数据各有不同的用处,可以按自己的需求决定按哪列数据作为排序字段。

在Activity的右侧,部分还带有Source Map链接,点击之后可以定位到相应操作对应的代码。使用它可以比较方便地定位到具体的代码。

推荐使用development版本的前端资源,如webpack-dev-server构建出来的版本,因为一般它的source map更准确一些。使用production模式带source-map的版本也行。

"Call Tree"中的内容,在"Bottom-Up"中也能看到,无明显的区别。

"Event Log"中的内容,是按顺序记录的事件日志,数据比较多。常见的优化级别中一般用不到它。如果是比较大型的应用,打开它可能会直接导致Chrome卡死。

注意上面的截图中,各个Activity有标注各自的颜色,它和Summary中的颜色是对应的,根据颜色可快速判断出它的类型是脚本、渲染或加载等。

时间条

另一个比较重要的区域,是最上方的时间条区域。

image-20201222165136156

如果开启了"Screenshots"选项,则鼠标浮动在任意一个点都能看到当时的截图。

同样是根据颜色,我们可以判断出在当前选中范围内,大部分的时间是黄色的脚本执行时间,还有一部分紫色的是渲染时间。另外还有一些空白的区域,一般是存在异步操作,如网络请求。

在时间条区域中,可以任意选定范围,下面的"Summary"、"Bottom-Up"等信息都会随着范围的变化自动更新。

网络

image-20201222165155874

在时间条的下方,会有一块网络请求区域。它能展示出各个请求的起始时间和截止时间。

在浏览器的Network页签中本身就能看到请求时间瀑布流,如果单纯的分析网络请求的话,在Network页签中查看也可以。

在查看网络请求的时候,可以重点关注下是不是有明显的独占一段时间的请求,或者有没有明显的前后关系,这说明很可能出现了串行等待的情况。

诊断问题

首先在时间条中选择可疑的范围,针对性地分析问题。

以一个实际项目为例:

image-20201222165211004

从时间条中可看出,有多处紫色的区域。根据刚刚的介绍,我们知道它是渲染过程。这些渲染过程明显地比一般的网站要多一些。

先选定一块紫色的区域,然后查看相应的Bottom-Up信息。

image-20201222165249170

选定区域后,可以看出90%多的时间都是在 Recalculate Style,同时后面还有堆栈信息。点击堆栈信息之后跳转到相应的位置,发现了如下的代码:

1function getStyle(el, property) {
2  return +getComputedStyle(el).getPropertyValue(property).replace('px', '');
3}

可以看出,这里的性能瓶颈是 getStyle函数中调用 getComputedStyle,触发了reflow,导致性能比较差。

解决办法就是减少它的调用次数,或者修改此处的逻辑。

再看一个JS的例子,先选定一块黄色区域,再查看"Bottom-Up"信息:

image-20201222165315843

从上图中也能看出,Activity是可以展开调用树的,和Call Tree页签类似。展开到熟悉的代码后停止,即可定位到出问题的地方。

找到相应行之后,点击右侧的Source Map链接,即可定位到具体的代码。


以上。