课外加餐:3 | 加载阶段性能:使用 Audits 来优化 Web 性能
前言:该篇说明:请见 说明 —— 浏览器工作原理与实践 目录
作为一名前端工程师,除了需要编写功能性的代码以外,还需要关注 Web 应用的性能问题,我们应该有能力让 Web 应用占用最小的资源,并以最高性能运行,这也是前端工程师进阶的必要能力。既然性能这么重要,那么进来聊聊 Web 性能问题。
到底什么是 Web 性能?
我们看下 wiki 对 Web 性能的 定义。(反正我是打不开)
Web 性能描述了 Web 应用在浏览器上的加载和显示的速度。
因此,讨论 Web 性能 其实就是讨论 Web 应用速度。关于 Web 应用的速度,需要从两个阶段来考虑:
- 页面加载阶段
- 页面交互阶段
在本文中,会将焦点放到第一个阶段:页面加载阶段的性能,在下篇文章中,则会重点分析页面交互阶段的性能。
性能检测工具:Performance VS Audits
要想优化 Web 的性能,就需要有监控 Web 应用的性能数据,那如何监控呢?
如果没有工具来模拟各种不同的场景并统计各种性能指标,那么定位 Web 应用的性能瓶颈将是一件非常困难的任务。幸好,Chrome 为我们提供了非常完善的性能检测工具:Performance 和 Audits ,它们能够准确统计页面在加载阶段和运行阶段的一些核心数据,诸如任务执行记录、首屏展示花费的时长等,有了这些数据就能很容易定位到 Web 应用的 性能瓶颈。
首先 Performance 非常强大,因为它提供了非常多的运行时数据,利用这些数据就可以分析出来 Web 应用的瓶颈。但是要完全学会其使用方式却是非常有难度的,其难点在于这些数据涉及到了特别多的概念,而这些概念又和浏览器的系统架构、消息循环机构、渲染流水线等知识紧密联系在了一起。
相反,Audtis 就简单了很多,它将检测到的细节数据隐藏在背后,只提供给我们一些直观的性能数据,同时,还会给我们提供一些优化建议。
Performance 能让我们看到更多细节数据,但是更加复杂,Audits 就比较智能,但是隐藏了更多细节。为了能够让你循序渐进地理解内容,所以本节先从简单的 Audits 入手,看看如何利用它来检测和优化页面在加载阶段的性能,然后在下一节再来分析 Performance。
检测之前准备工作
不过在检测 Web 的性能指标之前,还要配置好工作环境,具体地讲,你需要准备以下内容:
- 首先准备 Chrome Canary 版的浏览器,Chrome Canary 是采用最新技术构建的,它的开发者工具和浏览器特性都是最新的,所以我推荐你使用 Chrome Canary 来做性能分析。当然你也可以使用稳定版的 Chrome。
- 然后需要在 Chrome 的隐身模式下工作,这样可以确保安装的扩展、浏览器缓存、Cookie 等数据不会影响到检测结果。
利用 Audits 生成 web 性能报告
注:Audits 现在在浏览器中 是 Lighthouse 板块,升级了。
环境准备好之后就可以生成站点在加载阶段的性能报告了,这里拿 B 站 作为分析的例子。
- 首先打开浏览器的隐身窗口(其实就是无痕模式),Windows 系统下面的快捷键是 Control + Shift + N,Mac 系统下的快捷键是 Command + shift + N
- 然后在隐身窗口中输入 B 站的链接。
- 打开 Chrome 的开发者工具,选择 Audits 标签(现在是 Lighthouse 标签)
最终打开的页面如下:(后面会将 Audits 都改成 Lighthouse)
Audits 界面 / Lighthouse 界面
观察上图中的 Lighthouse 界面可以看到,在生成报告之前需要先配置 Lighthouse,配置模块主要由两部分组成,一个是监测类型(Categories),另一个是设备类型(Device)。
监控类型(Categories)是指需要监控哪些内容,这里有五个对应的选项,它们的功能分别是:
- 监测并分析 Web 性能(Performance)
- 监测并分析 PWA(Progressive Web App)程序的性能
- 监测并分析 Web 应用是否采用了最佳实践策略(Best practices)
- 监测并分析是否实施了无障碍功能(Accessibility),无障碍功能让一些身体有障碍的人可以方便地浏览 你的 Web 应用
- 监测并分析 Web 应用是否实施了 搜索引擎优化(SEO)
本文只需要关注 Web 应用的加载性能,所以勾选第一个 Performance 选项就可以了。
再看设备部分(Device),它有两个选项,Mobile 选项是用来模拟移动设备环境的,另一个 Desktop 选项是用来模拟桌面环境的。这里选择移动设备选项,因为目前大多数流量都是由移动设备产生的,所以移动设备上的 Web 性能显得更加重要。
配置好选项后就可以点击 Generate report 按钮来生成报告了。
解读性能报告
点击生成报告的按钮后需要等待下,Lighthouse 生成最终的分析报告如下:
生成的报告图
观察上图的分析报告,中间圆圈的数字表示该站点在加载过程中的总体 Web 性能得分,总分是 100 分。目前的得分是 53 分,表示该站点加载阶段的性能还有很大的提升空间。
Lighthouse 除了生成性能指标外,还会分析该站点并提供很多优化建议,我们可以根据这些建议来改进 Web 应用以获得更高的得分,进而获得更好的用户体验效果。
既能分析 Web 性能得分又能给出优化建议,所以 Lighthouse 的分析报告还是非常有价值的,那么接下来就来解读下 Lighthouse 生成的性能报告。
报告的第一部分是性能指标(Metrics),如下图所示:
性能指标
观察上图可以发现性能指标下一共有六项内容,这六项内容分别对应了从 Web 应用的加载到页面展示完成的这段时间中,各个阶段所消耗的时长。在中间还有一个 View Original Trace 按钮,点击该按钮可以跳转到 Performance 标签,并且查看这些阶段在 Performance 中所对应的位置。最下方是加载过程中各个时间段的屏幕截图。
报告的第二部分是可优化项(Opportunities),如下图:
可优化项(Opportunities)
这些可优化项是 Lighthouse 发现页面中的一些可以直接优化的部分,你可以对照 Lighthouse 给的这些提示来优化 Web 应用。
报告的第三部分是 手动诊断(Diagnostics),如下图:
手动诊断(Diagnostics)
在手动诊断部分,采集了一些可能存在性能问题的指标,这些指标可能会影响到页面的加载性能,Lighthouse 把详情列出来,并让你依据实际情况来手动排查每一项。
报告的最后一部分是 运行时设置(Runtime Settings),如下图:
注释:该部分在目前的 Chrome 中没看到了,现在的最后部分是:Passed Audits 。现在的部分会在后面补充,这是列出老师说的图 和 解说。
以前的 运行时设置(Runtime Settings)
观察上图,这是运行时的一些基本数据,如果选择移动设备模式,你可以看到发送网络请求时的 User Agent 会变成设备相关信息,还有会模拟设备的网速,这个体现在网络限速上。
根据性能报告优化 Web 性能
现在有了性能报告,接下来就可以依据性能报告来分析如何优化 Web 应用了。最直接的方式是想办法提高性能指标的分数,而性能指标的分数是由六项指标决定的,它们分别是:
- 首次绘制(First Paint) FP
- 首次有效绘制(First Meaningfull Paint) —— 现在没有这个了 FMP
- 首屏时间(Speed Index)
- 首次 CPU 空闲时间(First CPU Idle)—— 现在没有这个了
- 完全可交互时间(Time to Interactive)
- 最大估计输入延时(Max Potential First Input Delay)——现在没有这个了
现在变成了:
- 首次绘制(First Paint)
- 首屏时间(Speed Index)
- 最大内容绘制(Largest Contentful Paint) LCP —— add
- 完全可交互时间(Time to Interactive) TTI
- 总阻塞时间(Total Blocking Time) TBT —— add
- 累积布局偏移(Cumulative Layout Shift) CLS —— add
那么接下来会逐一分析每个指标的含义,并讨论如何提升指标的数值。这几项都是在页面加载过程中的性能指标,所以要弄明白每个指标的具体含义还得结合页面的加载过程来分析。如下图:从页面的加载到展示的过程图:
页面加载过程
观察上图可以发现,在渲染进程确认要渲染当前的请求后,渲染进程会创建一个空白页面,我们把创建空白页面的这个时间点称为 First Paint,简称 FP。
然后渲染进程继续请求关键资源,在《25 | 页面性能:如何系统地优化页面?》一文中介绍过关键资源,并且知道了关键资源包括了 JS文件和 CSS 文件,因为关键资源会阻塞页面的渲染,所以需要等待关键资源加载完成后才能进一步执行页面的绘制。
上图中,bundle.js 是关键资源,因此需要完成加载之后,渲染进程才能执行该脚本,然后脚本会修改 DOM,引发重绘和重排等一系列操作,当页面中绘制了第一个像素时,我们把这个时间点称为 First Content paint ,简称 FCP。
接下来继续执行 JS 脚本,当首屏内容完全绘制完成时,我们把这个时间点称为 Largest Content Paint,简称 LCP。
在 FCP 和 LCP 之间,还有一个 FMP,这个是首次有效绘制,由于 FMP 计算复杂而且容易出错,现在不推荐使用该指标,所以这里不做过多介绍了。
接下来 JS 脚本执行结束,渲染进程判断该页面的 DOM 生成完毕,于是触发了 DOMContentLoad 事件。等所有资源都加载结束后,再触发 onload 事件。
好了,以上就是页面在加载过程中各个重要的时间节点,了解了这些时间节点,我们就可以来聊聊性能报告的各个指标的含义并讨论如何优化这些指标。
先来分析下 第一项指标 FP,如果 FP 时间过久,那么直接说明了一个问题,那就是页面的 HTML 文件可能由于网络原因导致加载时间过久,这块具体的分析过程可以参考《21 | Chrome 开发者工具:利用网络面板做性能分析》一文。
第二项是 FMP,上面也提到过由于 FMP 计算复杂,所以现在不建议使用该指标了,另外由于 LCP 的计算规则简单,所以推荐使用 LCP 指标,具体文章可以参考这里(链接打不开)。不过不管是 FMP 还是 LCP,优化它们的方式都是类似的,你可以结合上图,如果 FMP 和 LCP 消耗时间过久,那么有可能是加载关键资源花的时间过久,也有可能是 JS 执行过程中所花的时间过久,所以我们可以针对具体的情况来具体分析。
第三项是首屏时间(Speed Index),这就是上面提到的 LCP,它表示填满首屏页面所消耗的时间,首屏时间的值越大,那么加载速度越慢,具体的优化方式同优化第二项 FMP 一样。
第四项是首次 CPU 空闲时间(First CPU Idle),也称为 First interactive,它表示页面达到最小化可交互的时间,也就是说并不需要等到页面上的所有元素都可交互,只要可以对大部分用户输入做出响应即可。要缩短首次 CPU 空闲时长,就需要尽可能快的加载完关键资源,尽可能快地渲染出首屏内容,因此优化方式和第二项 FMP 和第三项 LCP 是一样的。
第五项是完全可交互时间(Time to Interactive),简称 TTI,它表示页面中所有元素都达到了可交互的时长。简单理解就这时候页面的内容已经完全显示出来了,所有的 JS 事件已经注册完成,页面能够对用户的交互做出快速响应,通常满足响应速度在 50 毫秒以内。如果要解决 TTL 时间过久的问题,我们可以推迟执行一些和生成页面无关的 JS 工作。
第六项是最大估计输入延时(Max Potential First Input Delay),这个指标是估计你的web 页面在加载最繁忙的阶段,窗口中响应用户输入所需的时间,为了改善该指标,可以使用 WebWorker 来执行一些计算,从而释放主线程。另一个有用的措施是重构 CSS 选择器,以确保它们执行较少的计算。
总结
本文的主要内容:
本文主要讨论如何优化加载阶段的 Web 应用的性能。
要想优化 Web 性能,首先得需要有 Web 应用的性能数据。所以接下来介绍了 Chrome 采集Web 性能数据的两个工具:Performance 和 Audits(现在的 Lighthouse),Performance 可以采集非常多的性能,但是其使用难度大,相反,Audits 就简单很多,它会分析检测到的性能数据并给出站点的性能得分,同时还会提供一些优化建议。
我们先从简单的工具上手,所以本文主要分析了 Audits 的使用方式,先介绍了如何使用 Audits 生成性能报告,然后解读了性能报告中的每一项内容。
大致了解了 Audits 生成的性能报告后,又分析 Web 应用在加载阶段的几个关键时间点,最后分析性能指标的具体含义以及如何提高性能指标的分数,从而达到优化 Web 应用的目的。
通过介绍知道了 Audits 非常适合用来分析加载阶段的 Web 性能,除此之外,Audits 还有其他非常实用的功能,比如可以检测我们的代码是否符合一些最佳实践,并给出提示,这样就可以根据Audits 的提示来决定是否需要优化我们的代码。
思考
在文中又分析 Web 应用在加载阶段的几个关键时间点,在 Audits 中,通过对这些时间点的分析,输出了文中介绍的六项性能指标,其实这些时间点也可以通过 Performance 的时间线(Timelines)来查看。
任务:提前熟悉下 Performance 工具,并对照文中加载阶段的几个时间点来熟悉下 Performance 的时间线(Timelines)。
记录
1、文中:先来分析下第一项指标 FP,如果 FP 时间过久,那么直接说明了一个问题,那就是页面的 HTML 文件可能由于网络原因导致加载时间过久。
这里 FP 应该是 FCP 吧?FP 创建空白界面跟网络有关系吗?
作者回复:也是有关系的,因为浏览器还需要根据 HTTP 响应头来判断要不要继续执行导航流程!
2、文中介绍了一些性能指标,比如 FP,FCP等,但是这些数据如何使用 performance.timing 里的数据给统计出来了?
比如首屏时间,这个结束点在工具里很容易看到,但是如何拿到这个点的时间数据了?
作者回复:浏览器统计的方式非常复杂,FP 是通过 GPU 是否开始绘制来统计的,FCP 又是在其他的地方统计的,源代码如何统计的细节我也没详细查看,不过这些数据你可以通过JS 接口来获取到,具体你可以搜索 Paint Timing API