Web/13-前端性能优化/01-前端性能分析工具和指标.md
2021-04-27 12:54:33 +08:00

697 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 性能指标和优化目标之加载
性能指标我们在性能优化过程中可以参考的标准这些标准都是业界或者前人总结出来的指导性经验我们可以参考这些指标去指导我们自己的优化
### 打开网站的初体验
我们以淘宝网站为例按下F12打开浏览器的调试模式
![](http://img.smyhvae.com/20210115_1601.png)
上图中鼠标右键点击刷新图标或者鼠标长按刷新图标松开鼠标后会弹出三个选项我们选择最后一个选项清空缓存并硬性重新加载
补充这三个选项都是在调试模式下按下F12弹出调试面板才会出现的
浏览器的DevTools初印象
![](https://img.smyhvae.com/20210115_1617.png)
上图中打开 chrome 调试工具点开设置icon下面的四个选项中除了Group by frame之外其他的三个选项都可以勾选上
我们可以看到淘宝网站的一些指标
- 总资源量是 1.3M
- DOM加载完成时间DOMContentLoaded511ms这是一个很关键的指标
- 其他资源的总加载时间是 1.05
我们再来对比一下京东的
![](http://img.smyhvae.com/20210116-1357.png)
### 保存快照
network里的信息挺多我们可以将其保存下来留着以后做分析做对照
![](http://img.smyhvae.com/20210115-1723.png)
如上图所示我们可以在 network 的空白处右键选择Save all as HAR with content network 信息保存为 **HAR**文件格式
**HAR是一种标准的Web格式用户保存性能测试的结果里面的数据是json格式**
我们可以使用第三方的 HAR 分析软件来打开 HAR 文件比如
- [Google 提供的 HAR 分析器](https://toolbox.googleapps.com/apps/har_analyzer/?lang=zh-CN)
- Fiddler 抓包工具
注意HAR 文件包含了一些敏感信息
![](http://img.smyhvae.com/20210115-1733.png)
### 瀑布图 Waterfall
![](http://img.smyhvae.com/20210115_1618.png)
瀑布图可以非常直观地把网站的加载过程用自上而下的方式表达出来就像瀑布一样
瀑布图有两中解读方式一种是横向看一种是纵向看
**1横向看**
横向看的是具体的资源每一行代表某个资源的加载信息里面有一些色块来表达加载的过程每个块的颜色不同也就是说资源的下载不是单一的过程而是经历了很多环节
为了了解资源的具体加载过程我们把鼠标悬浮在第一个资源的色块上可以看见一个详情列表
![](http://img.smyhvae.com/20210115_1632.png)
1等待
- Queueing排队浏览器会对资源的请求做优先级排序
2连接
- DNS LookupDNS域名解析每个资源都有域名对域名做DNS解析然后找到对应服务器的IP地址
- initial connection客户端和服务器之间建立TCP连接
- SSL证书该网站为了保证安全性使用了 https 协议启用了SSL证书启用之后需要做安全认证SSL协商这个过程也会耗时到这里位置我们可以看到在请求资源之前有很多的前置步骤
3请求和响应
- Request sent到这一步真正开始请求资源
- Waiting**TTFB**资源从请求到响应有一个等待的时间
- Content Download收到响应后资源的下载时间如果值越大表明下载时间越长有些同步加载的资源会造成阻塞导致网页的整体加载时间过长让用户等待太久
**TTFB** 是一个很重要的指标它表示的是请求发出到响应到底要经历多久TTFB 可以给我们一个很直观的感受我们网站的请求和响应到底是快还是慢很大程度上是由 TTFB 决定
影响 TTFB 的因素是什么呢比如
- 后台的处理能力的响应速度
- 网络状况是否有网络延迟
**2纵向看**主要看两点
1看资源与资源之间的联系如果发生阻塞说明资源可能是串行地按顺序加载可以**按需要适当调整为并行**
2看关键的时间节点Waterfall 中有**两根时间线**蓝色的线是 DOM 加载完成的时间红色的线是所有资源加载完成的时间
## 性能指标和优化目标之交互
上面的内容讲的是**加载**的性能还有一个需要关注的性能指标是**交互**也就是网站加载完成后用户真正开始使用这个网站过程中的的交互体验
关于交互体验的性能我们需要关注的是
- 交互动作的**响应时间**要短比如点击按钮后的弹窗在搜索框里输入关键字后的搜索结果
- 页面滚动要流畅可以查看 FPS 帧率
- 异步请求接口的完成时间要短比如关注/取关主播的响应领取红包的操作
### FPS帧率FRS
这里首先科普两个概念
- 刷新率显示器每秒有多少帧画面大多数显示器的刷新率是60帧/即60hz
- 帧率FPSframes per second视频或者动画的内容本身每秒有多少帧由显卡输出帧率
上面的两个参数中不要把刷新率帧率弄混了刷新率是屏幕的参数帧率是图像视频等内容的参数人眼最终看到的效果是以最低的参数为准的
目前市场主流手机和电脑屏幕的刷新率基本都是60Hz即每秒显示60帧画面也就是说当我们在使用手机的时候本质上是手机在连续播放一张张静态图片每秒播放60张让肉眼误认为眼前的画面在动
![](http://img.smyhvae.com/20210107_2115.gif)
持续滑动的过程中如果页面输出到显示器的帧率低于60帧/则人眼会感觉卡顿
那么在浏览器中如何实时显示内容的 FPS 参数呢打开浏览器的控制台后按住快捷键Cmd + Shift + P然后输入 `frame`选择`Show frames per secondFPS meter`如下
![](http://img.smyhvae.com/20210115-1930.png)
![](http://img.smyhvae.com/20210115-2146.png)
**温馨提示**
2020年7月起chrome 官方已经取消了 fps参数的显示改为了 [FRS](https://twitter.com/addyosmani/status/1281483292026400768)
![](http://img.smyhvae.com/20210115-2006.png)
FRS参数观察的是丢帧率
![](http://img.smyhvae.com/20210115-2010.png)
Chrome官方给我们提供了下面这个网站用于观察 FPS 效果
- <http://googlesamples.github.io/web-fundamentals/tools/chrome-devtools/rendering-tools/forcedsync.html>
如果实在想要看fps我们可以借助第三方的 [chrome 插件]()来查看 fps参数
## RAIL 模型测量性能
RAIL 模型是Google提出的可以量化性能的测量**标准**我们做性能优化时要尽可能到这个标准
在做性能优化的时候我们需要有人告诉我们做到多好才算好有没有一些通用的标准 RAIL 模型 可以给我们带来量化的指标
**RAIL 模型包括四个方面**
![](http://img.smyhvae.com/20210115-2027.png)
- Response响应
- Animation动画
- Idle空闲时间
- load加载
参考链接
- [[Web翻译]用RAIL模型测量性能](https://juejin.cn/post/6872474167543857165)
- <https://web.dev/rail/>
**RAIL 的目标**
- 让良好的用户体验成为性能优化的目标
接下来我们再看看看 RAIL 的评估标准
### 1响应
**目标**处理用户发起的响应应该在 50ms 内完成
**准则**
- 在50毫秒内处理用户输入事件这适用于大多数输入如点击按钮切换表单控件或启动动画这不适用于触摸拖动或滚动
- 对于需要超过50毫秒才能完成的操作需要提供反馈
![](http://img.smyhvae.com/20210115-2039.png)
如上图所示Google经过大量研究发现用户能够接受的最高延时是100ms所以从用户发起交互请求输入任务前端最好能在100ms内给出反馈
**但是我们的预算只有50毫秒**因为应用程序在接收到输入任务的时候不一定会马上着手处理它可能还有其他工作正在进行这意味着当前的输入任务可能需要排队50ms左右所以我们真正能处理这个请求的时间并没有100ms
### 2动画
**目标**在10毫秒或更短的时间内制作出动画中的每一帧100/
我们知道当动画的帧率是 >= 60/ 的时候人眼才不会觉得卡顿此时的理论值为 1000毫秒/60 = 16.6 毫秒/
10毫秒和16毫秒之间隔了6秒这6秒是什么呢因为浏览器需要大约6毫秒的时间来渲染每一帧所以每一帧的准则建议是10毫秒而不是 16.6毫秒
假设动画本身是60帧/那么最终渲染出来的效果可能只有 45/
**广义的动画**
动画不仅仅是花哨的UI效果每一种交互都被认为是动画比如
- 视觉动画
- 滚动
- 拖动平移元素放大图片等
### 3空闲时间
**目标**最大化闲置时间增加页面在50毫秒内响应用户输入的几率
这个空闲时间是和上面的第一点响应是结合在一起的只有空闲足够多当用户的交互来的时候我们才能有足够的时间进行处理
**准则**
- 利用空闲时间做延迟加载例如页面在初始化的时候尽可能少的加载数据然后利用空闲时间加载其余部分
- 在空闲时间内处理任务时间不能超过50毫秒否则就阻塞了用户做其他的输入请求导致卡顿
- 如果用户在闲置时间工作期间与页面进行交互那么这个交互应始终处于最高优先级并中断闲置时间工作
### 4加载
**目标**在5秒或更短的时间内加载页面并可以交互
**准则**
- 这里的5秒包括加载解析渲染并确保用户可以交互
- 加载的过程中可以使用loading框进度条骨架屏等方式缓解用户焦虑
## 使用Chrome DevTools 分析性能
现在主流的性能测量工具
- Chrome DevTools开发调试分析性能
- Lighthouse 网站整体质量评估
- WebPageTest给网站提供多个地点的测试以及全面的性能报告
这一段我们先来讲一讲 Chrome DevTools
大家平时在用 Chrome DevTools 的时候一般使用来开发调试查看 DOMcss接口请求等但其实这个工具非常强大
### size文件大小分析
![](http://img.smyhvae.com/20210116-0946.png)
可以把size从到小排序看看哪个资源的文件较大
另外上图中的横线处说明该文件在网络传输的时候会做压缩125kb拿到资源之后再解压还原526kb
### performance性能表现
![](http://img.smyhvae.com/20210116-0959.png)
preformance的两个作用
- Record button记录页面加载用户交互等全过程直到我们手动点击停止按钮
- Reload button记录页面从刷新到资源加载完成的过程会自动停止记录
参数解读
- Timing关键的时间节点
- Main主线程做了哪些任务以及调用关系
Timing参数中尤其注意看`DCL`DOMContentLoaded即DOM加载完成的时间节点我们可以通过`Main`参数看看DOM在加载完成之前都做了些什么事情很有可能就是这些事情导致 `DCL`的时间过晚
我们可以翻到`Main`里的最后一行即最终调用的位置往往这个位置就是我们自己写的代码
### Diable cache
![](http://img.smyhvae.com/20210116-1014.png)
上图中的`Diable cache`是一个很重要的设置选项
勾选`Diable cache`
- 不走缓存相当于页面初次访问
- 如果你希望改的代码立即生效就一定要勾选上
不勾选`Diable cache`
- 走缓存相当于页面二次三次访问
- 很多时候我们需要关心用户在第二次第三次访问时候他的访问速度如何性能如何我们设置的缓存有没有生效此时就不要勾选上
### 模拟网络情况
![](http://img.smyhvae.com/20210116-1023.png)
模拟网络状况自定义参数
![](http://img.smyhvae.com/20210116-1026.png)
### Performance monitor
![](http://img.smyhvae.com/20210116-1032.png)
### 快捷键ESC
按住快捷键ESC会列出其他常用的功能菜单
![](http://img.smyhvae.com/20210116-1028.png)
## 使用LightHouse分析性能
我们之所以使用不同的性能测量工具是因为他们都有不同的特点这一段要讲的 lighthouse 既可以帮我们生成简易的测试报告还可以给出一些针对性的优化建议后面要讲的 WebPageTest 可以帮我们生成详细的性能测试报告
我们先来看看 Lighthouse
### Lighthouse 介绍
![](http://img.smyhvae.com/20210115-1739.png)
lighthouse chrome 浏览器的一个性能测量工具我们先来看看它的性能指标至于它具体使用后续的内容再详细介绍
淘宝跑分举例
![](http://img.smyhvae.com/20210115-1758.png)
京东跑分举例
![](http://img.smyhvae.com/20210115-1759.png)
Lighthouse 跑分里最重要的两个指标如下
- **First Contentful Paint白屏时间****从白屏到第一次出现内容的时间**我们可以看到上面提供了一些加载过程的截图10屏里如果只有1到2屏是白屏说明体验还是可以的
- **Speed Index**速度指数
我们不需要关心这个指数是怎么来的因为背后涉及一套很复杂的公式我们暂时只需关注这个数值
Speed Index 标准为4秒超过4秒算比较慢的我们测的淘宝的 speed index 是0.5s很快了但我们要结合网站本身的业务来**权衡**并不是分数越高性能越高比如百度这样的网站页面上的内容很少测出来的分数肯定很完美而淘宝需要展示很多内容给用户看所以这个指标只是一个指导作用并不一定能够达到最优的数值
Lighthouse 的分析结果里也给出了颜色标注
- 红色比较严重的性能问题
- 黄色需要做适当优化
- 绿色说明性能表现很好
另外Lighthouse 还会给出一些优化建议
- Opportunities:优化建议
- Diagnostics问题诊断
- Passed audits表示这部分没有问题
### 举例确认某个JS 是否必须在首屏加载
就拿B站来举例来看看它的lighthouse报告
![](http://img.smyhvae.com/20210116_0107.png)
上图中给出了一个优化建议有些JS文件不是首屏加载必须的
![](http://img.smyhvae.com/20210116_0108.png)
我们随便拿一个JS文件来测试比如上图中Header标签里的JS文件做法如下
![](http://img.smyhvae.com/20210116-0901.png)
如上图所示 chrome 控制台输入快捷键Cmd + Shift + P然后输入文本`block`选择`Show Network request blocking`
![](http://img.smyhvae.com/20210116-0903.png)
按照上面的步骤添加规则点击add后效果如下
![](http://img.smyhvae.com/20210116-0904.png)
然后我们切换到控制台的 network面板并刷新页面
![](http://img.smyhvae.com/20210116-0905.png)
然后观察这个js资源是不是首屏加载所必须的但我们也不能就此定论说这个资源一定可以延迟加载也许它就是想让页面在一开始loading的时候就捕获日志
对于我们自己的网站这个资源是首屏加载必须的吗一定要在第一时间加载吗需要根据特定的业务做衡量
### 通过npm运行 Lighthouse工具
```bash
# 安装
npm install -g lighthouse
# 执行
lighthouse https://www.jd.com
# 输出性能检测报告
Generating results...
html output witten to /Users/smyh/Documents/wpt-mac-agent/www.jd.com._2021-01-16_09-00-00.html
```
## 使用 WebPageTest 评估网站性能
程序员经常说的有句话是我这儿能打开啊我这儿不报错呀大家应该都懂这个梗这就是为什么我们要借助第三方的测试工具而不仅仅只是自己电脑上访问正常就ok了
我们需要借助 WebPageTest 这样的第三方测试工具去模拟各种用户的真实场景
### WebPageTest 使用
网址<https://www.webpagetest.org>
![](http://img.smyhvae.com/20210115-2203.png)
WebPageTest 在世界各地提供了非常多的服务器在每个服务器上部署了不同的浏览器可以让我们有针对性的做测试如果你做的是一款国际化网站那更有必要使用一下了
我们以JD网站举例
![](http://img.smyhvae.com/20210115-2225.png)
按照上面的选项配置完成后点击右侧的Start Test即可开始测试然后等待
![](http://img.smyhvae.com/20210115-2226.png)
### WebPageTest 报告分析
淘宝网站性能测试报告
- 2020年6月https://webpagetest.org/result/200616_JK_78eebda338285ffe0c2e154ca5032839/
- 2021年1月https://www.webpagetest.org/result/210115_DiCB_f1344d732760365151755e89765b2d37/
JD网站性能测试报告
- 2021年1月https://www.webpagetest.org/result/210115_DiGT_8d7370e91230b7d077e40b7aafb485a5/
拿到 WebPageTest 报告之后我们来看看报告里的几个重点指标
![](http://img.smyhvae.com/20210116_1314.png)
1摘要里的参数如上图
- First Byte第一个请求的响应时间可以反映后台的处理能力以及网络回路的情况
- Start Render从白屏到首次渲染的时间
- Speed Index速度指数
- **Total Blocking Time**页面被阻塞导致用户不能交互的累计时间
![](http://img.smyhvae.com/20210116_1315.png)
2详情里的参数**First View**
First View展示的是首次访问时总的加载时间这里面提供的瀑布图 chrome DevTools里提供的更为详细
点击进入 First View 的详情之后可以看到所有的资源请求都会在这里列出来如下
![](http://img.smyhvae.com/20210116_1316.png)
- page is Interactive页面在加载的过程中大部分时间段用户都是可以交互的这是非常有用的一个指标
- Brower Main thread浏览器主线程的占用情况可以看看空闲的时间多不多
- CPU UtilizationCPU的使用情况
- 多张图片的资源请求
![](http://img.smyhvae.com/20210116_1317.png)
上图中我们可以看到多张图片的开始请求时间都是相同的也就是说如果让资源做**并行加载**我们就可以加大地减少加载时间**最终所消耗的时间就由最大的图片来决定**这是一个很好的优化技巧至于具体是怎么实现的可以自行了解
另外我们看到有一部分的请求被高亮出来了
![](http://img.smyhvae.com/20210115-2250.png)
上面这张图的意思是302表示重定向也就是说这个资源已经不在原来请求的位置了需要重定向才能找到真实的位置这个地方其实可以做一个优化
> 不需要去访问之前的无效的资源可以直接去访问重定向后的那个资源
### 局域网部署 WebPageTest 工具
如果我们开发的页面还没有上线公网则无法访问这个时候我们也想通过WebPageTest看看网站的性能那要怎么办呢
我们可以在局域网部署 WebPageTest 工具具体方法可自行研究
## chrome插件PageSpeed Insights
另外google官方也有一个网址https://developers.google.com/speed/pagespeed/insights/?hl=zh-cn
但是这个网站在使用时经常挂掉
这个插件是2018年的已经好几年没更新了大家参考即可
## 实时动态测量性能的API
Chrome DevTools能够检测各种性能参数其实也是调用了一些性能相关的标准API我们自己也可以直接在代码里调用这些api
通过 `performance`对象提供的API我们可以实时的精细化自定义测量性能获取相应的参数也可以把这些性能参数打印到控制台或者实时上报给后台监控系统
### performance获取常见性能参数
常见性能参数计算公式如下
> 时间戳1减去时间戳2得到的差值就是我们想要看到的耗时
- DNS 解析耗时: domainLookupEnd - domainLookupStart
- TCP 连接耗时: connectEnd - connectStart
- SSL 安全连接耗时: connectEnd - secureConnectionStart
- 网络请求耗时 (TTFB): responseStart - requestStart
- 数据传输耗时: responseEnd - responseStart
- DOM 解析耗时: domInteractive - responseEnd
- 资源加载耗时: loadEventStart - domContentLoadedEventEnd
- First Byte时间: responseStart - domainLookupStart
- 白屏时间: responseEnd - fetchStart
- 首次可交互时间**TTI**: domInteractive - fetchStart
- DOM Ready 时间: domContentLoadEventEnd - fetchStart
- 页面完全加载时间: loadEventStart - fetchStart
- http 头部大小 transferSize - encodedBodySize
- 重定向次数performance.navigation.redirectCount
- 重定向耗时: redirectEnd - redirectStart
比如说如果我们想要获取 TTI参数代码可以这样写
```javascript
// 计算一些关键的性能指标
window.addEventListener('load', (event) => {
// Time to Interactive
let timing = performance.getEntriesByType('navigation')[0];
console.log(timing.domInteractive);
console.log(timing.fetchStart);
let diff = timing.domInteractive - timing.fetchStart;
console.log("TTI: " + diff); // 打印 TTI 参数
})
```
### 观察长任务
```javascript
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry)
}
})
observer.observe({entryTypes: ['longtask']})
```
### 页面可见性的状态监听
使用场景举例
- 比如说我们正在做一个视频网站或者游戏页面如果用户当前没有在看这个视频而是切换别的页面了此时我们可以对视频做节流等处理避免造成性能的浪费等用户再回到当前页面之后再恢复之前的状态
- 当设备进入待机模式时用户按下电源键关闭屏幕网站想要关闭设备声音
针对这种场景我们可以使用`visibilitychange`进行监听
```javascript
// 见面可见性的状态监听
let vEvent = 'visibilitychange';
if (document.webkitHidden != undefined) {
// webkit prefix detected
vEvent = 'webkitvisibilitychange';
}
function visibilityChanged() {
if (document.hidden || document.webkitHidden) {
console.log("Web page is hidden.")
} else {
console.log("Web page is visible.")
}
}
document.addEventListener(vEvent, visibilityChanged, false);
```
### 网络状况监听
使用场景举例
- 高清图片按需加载如果用户的网络条件较好就加载高清图片资源如果网络条件不好就加载文件较小的图片资源
代码举例
```javascript
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
var type = connection.effectiveType;
function updateConnectionStatus() {
// type是之前的网络状态connection.effectiveType是当前最新的网络状态
console.log("Connection type changed from " + type + " to " + connection.effectiveType);
type = connection.effectiveType;
}
connection.addEventListener('change', updateConnectionStatus);
```
打印结果举例
```
Connection type changed from 4g to 3g
```
### 检测元素的可见状态做曝光埋点
我们可以通过`IntersectionObserver`这个API来检测元素的可见状态
![](http://img.smyhvae.com/20210117_1635.png)
做曝光上报的埋点判断某个DOM或者某个楼层是否出现在视窗中出现了就收集数据上报给服务端
本质就是要计算某一元素和另一元素视窗的相对位置/相对可视状态然后进行一些操作一般是上报给服务端
参考
- [前端埋点之曝光实现](https://cnodejs.org/topic/5e0a0edb0696c446bf650dec)
- [点击埋点和曝光卖点的封装](https://github.com/Hugohui/vueTrackSdk)