性能优化3
第二节讲到了性能指标的出处,以及标准的粗略解读,本章就要开始进入正题。讲解各项指标。
通过第一章,我们知道一个网页要开始展现出来,需要先从服务端取得文档(html文件),第二章我们知道了,文档属于一种资源,而资源加载的过程可以通过Resource Timing看到,宏观上分为三大类:
1.文档加载相关 2.内容呈现相关 3.交互响应相关
一 文档加载相关
文档加载过程时间线如图,这里主要介绍三个指标:TTFB、DCL 和 Load 时间。
1.1 TTFB(Time to First Byte)
定义:浏览器从请求页面开始到接收第一字节的时间,这个时间段内包括 DNS 查找、TCP 连接和 SSL 连接。
1.2 DomContentLoaded(DCL)
定义:DomContentLoaded 事件触发的时间。当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像和子框架加载完成。
1.3 Load(L)
定义:onLoad 事件触发的时间。页面所有资源都加载完毕后(比如图片,CSS),onLoad 事件才被触发。
二 内容呈现相关
2.1 First Paint(FP)
定义:第一个像素绘制的时间,不包括默认的背景,感觉没什么用
测量方式不用说了吧,performanceAPI提供。
2.2 First Contentful Paint(FCP)
定义:首次内容绘制,绘制内容是指来自的DOM内容,可以是图像,文字,svg,canvas等等,
测量方式:PerformanceApi
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
console.log('FCP candidate:', entry.startTime, entry);
}
}).observe({type: 'paint', buffered: true});
2.2.1 How to improve FCP
1.减少资源的阻塞,例如不要把业务js放在顶部加载 2.压缩css和移除无用的css,可以使用purifyCss 3.pre-fetch dns链接 4.减小TTFB 5.避免多次重定向 6.preload必要的资源 7.避免巨大的网络负载 8.做好静态资源的缓存策略 9.避免过大的DOM,减少生成dom tree的时间 10.确保文本在Web字体加载期间保持可见 11.保持较低的请求计数和较小的传输大小
2.3 First Meaningful Paint (FMP)
定义:首次有意义的内容绘制时间,这里的有意义主要看网站,比如小说网站有意义的内容就是文字,漫画网站有意义的就是图片,如果是视频网站有效绘制就是视频,有用,但是现在很多性能测试工具已经不用这个指标了,换成了另外的指标了 Largest Contentful Paint,所以这里不再仔细介绍。
2.4 Largest Contentful Paint(LCP)
定义:可视区域中最大的内容元素呈现到屏幕上的时间,用以估算页面的主要内容对用户可见时间。这是一个新的指标,很多浏览器都没有实现。
如何测量:
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
}).observe({type: 'largest-contentful-paint', buffered: true});
2.4.1 How to improve LCP
1.采用PRRL模式
Push (or preload) 重要的资源.
Render:尽快的渲染初始路由页.
Pre-cache :预缓存资源,使用service worker等等.
Lazy load:懒加载剩下的资源和路由.
2.优化字体,图片,css,js 3.优化关键渲染路径
2.5 Speed Index(SI)
定义:这是一个表示页面可视区域中内容的填充速度的指标,可以通过计算页面可见区域内容显示的平均时间来衡量。
例如同样的一个页面:A在3秒的时候填充了百分之80的区域,B在3秒的时候也填充了百分之80的区域,5秒都完成了百分之百,但是A在1秒的时候已经完成了百分之80,B在3秒的时候才完成了百分之80;
通过计算可以得到
A:80% * 1 + 20% * 5 = 1.8
B:80% * 3 + 20% * 5 = 3.4
2.6 First Screen Paint(FSP)
定义:页面从开始加载到首屏内容全部绘制完成的时间,用户可以看到首屏的全部内容。
三 交互响应相关
3.1 Time to Interactive(TTI)
定义:从FCP开始,浏览器已经可以持续性的响应用户的输入。完全达到可交互状态的时间点是在最后一个长任务(Long Task)完成的时间, 并且在随后的 5 秒内网络和主线程不存在longtask或者不超过一个网络请求。
1.从FCP开始
2.longtask后五秒内不再有longtask产生并且不超过一个网络请求
3.在五秒处先前搜索到最后一个longtask结束的时间点
4.从FCP到这个longtask结束的时间点就是TTI
3.2.1 How to improve TTI
1.压缩代码 2.预链接必要的源 3.预加载css等资源 4.按需加载第三方的包 5.减少关键资源的请求深度,例如请求一层嵌套一层 6.减少js执行时长,优化代码 7.减少主线程中的工作,例如只加载必要的代码,使用节流处理频繁的input,减少css的资源查找等等 8.减少请求,压缩请求的内容使用gzip等等
3.2 Total Blocking Time(TBT)
定义:在TTI中,所有的longtask减去50ms的累计值,优秀的TBT应该控制在300ms以下。 当一个task超过50ms的时候就会导致UI卡顿等一些问题。
3.2.1 How to improve TBT
1.减少第三方包的依赖,
按需加载,能简单实现的 尽量不要安装一个包
2.优化代码,减少单个js任务的执行时间
禁止多层嵌套,可以改变数据结构,或者用空间换时间
3.最大成都的减少住主线程的工作
1.优化第三方js
2.debounce Input 操作
3.使用web worker
4.减少样式计算的复杂性
5.避免重回和重排的工作
6.提取关键css,延迟非关键的css加载
7.注意样式的书写,尽可能的不要写太多的Layout
8.更好的tree-shaking和code_split
4.控制请求的个数,并且降低传输的内容
3.3 First Input Delay (FID)
定义:当用户第一次与页面交互时到能够响应用户行为的时间,例如点击链接,输入表单,点击一个按钮。通常应该控制在100ms
测试方法:
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
const delay = entry.processingStart - entry.startTime;
console.log('FID candidate:', delay, entry);
}
}).observe({type: 'first-input', buffered: true});
3.3.1 How to improve FID
1.减少第三方包的依赖 2.减少js执行时间 3.降低主线程序的工作 4.保持低请求数和资源传输大小
3.4 Cumulative Layout Shift (CLS)
定义:在一个页面的生命周期中,所有元素发生突然位移的分数总和。
看起来很难理解,举个例子🌰:
1.当我们要去点击一个元素的时候,突然这个元素向下偏移了。导致我点击到了别的东西。
2.突然间页面出现了一个元素把其他的元素挤跑了
分数如何计算的
例如一个元素在第一帧的时候,占据了viewport的上面百分之50,在下一帧就跑到了页面的最底部,那么这个元素并集所占viewport的百分比就是1,那么得分就是1分;
js中如何测量:
let cls = 0;
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) {
cls += entry.value;
console.log('Current CLS value:', cls, entry);
}
}
}).observe({type: 'layout-shift', buffered: true});
3.4.1 How to improve CLS
1.设置图片视频的大小,保证加载前和加载后占地面积一致 2.禁止在已存在内容在中插入内容 3.使用transform动画替代改变布局导致的动画
测试工具
目前主要的测试用具有
-
Chrome DevTools
-
Lighthouse
-
WebPageTest
-
web-vitals 这是一个js库,我打算用它来做一个性能检测的平台,性能监控的功能,不知道方案是否可行 还有一些其他的就不一一列举了。
总结
通过以上性能指标的介绍,大概总结出提高性能指标的手段主要有以下一些内容:
- 减少第三方包的依赖
- 按需加载包,路由
- 资源嗅探prefetch, preload, dns-prefetch
- 压缩资源
- 使用存储工具缓存资源,静态资源做好缓存策略
- 减少传输体的大小
- 减少重回和重排
- 减少重定向
- 降低dom嵌套和css嵌套
- 加载必要的css js资源。非必要的采用懒加载
- 使用debounce和throttle
- 降低主线程的占用时间
- 保持低的请求数量 等等
一名在前线奋斗的菜鸟前端,希望和大家一起学习,进步~
1.关注前端工兵,不定时发放极客时间福利哦;
2.觉得文章不错,点个关注,再点个再看,也可以和我交流,共同进步;