背景
大家都去医院体检过吧~是不是经常看不懂一些化验指标,直接跳过看医嘱:“未见异常”。是不是很真实,但是今天并不是告诉大家怎么看体检报告。其实我们前端也是有一些方法给页面进行“体检”,但要是有些同学没有专门看过的话,对于一些数据可能会问:“这玩意是怎么算的?”,这篇文章的目的就是和大家一起解读报告。
用什么可以方式获得页面指标
其实先在有很多轮子可以用了,如果是想要快速实现的话,可以直接用现成的工具,当然有兴趣的同学也可以手动计算一下。这里我们不重点介绍工具。
lighthouse
什么是lighthouse
lighthouse是一款Google开发的一款能够分析页面网络情况,以及一些性能指标的开源工具。并且能够提出一些可执行的意见,帮助开发者进行优化。
怎么用lighthouse
我们使用lighthouse一些常见的方式如下:
- 浏览器的开发者工具
- 命令行
这两个的使用场景我个人认为:假如你只是单纯的开发完想看看这个页面的指标,那就直接用开发者工具内的lighthosue就行了。如果你是需要对一批页面进行测试,那可以考虑用命令行的方式,而且命令行也有好处,就是可以直接通过脚本定时生成报告,让大家互相攀比起来.....然后偷偷摸摸进行优化。
如果大家想了解定时生成报告的,可以留言催更,哈哈哈哈。
performance
什么是performance
performance也是浏览器提供的一个工具,以chrome为例,开发者可以在里边查看页面的加载的时间,甚至一些资源的加载顺序,甚至可以查到各种栈的调用等。
怎么用performance
在开发者工具找到performance,然后选择刷新页面并录制就行了。你也可以设置网络状态来进行测试。
window.performance
什么是window.performance
文档中的解释是:
Web Performance API允许网页访问某些函数来测量网页和Web应用程序的性能,包括 Navigation Timing API和高分辨率时间数据
怎么用window.performance
这个就是根据逻辑来处理了,但是一般情况下我们是放在页面加载结束之后在进行调用,performance是直接挂载到window上的。推荐使用listener去监听load事件,避免函数被覆盖。
报告各项指标分别表示什么含义
lighthouse一共有4项主要的指标,分别是:
- Performance 性能
- Accessibility 无障碍
- Best Practices最佳实践
- SEO 搜索引擎优化
当然,这次我们主要讲的是我们比较常用的performance模块。
Performance访问流程图
大家对下边这张图应该不太陌生吧~,这个其实就是performance访问的流程图,给大家介绍一些常用的字段,方便后边解释指标的时间是怎么计算的。
- navigationStart: 当前页面启动的时间,可以理解为处理完地址开始请求的那一刻
- fetchStart:浏览器发起HTTP请读取文档的时间
- domainLookupStart:DNS查询开始
- domainLookupEnd:DNS查询结束
- connectStart:开始建立TCP连接,也就是开始进行握手
- connectEnd:TCP建立完成
- requestStart:发出HTTP请求的一瞬间
- responseStart:返回第一个字节的时间
- responseEnd:请求结束的时间
- domLoading:开始解析DOM的时间
- domInteractive:DOM解析完成,并创建好DOM树
- domContentLoadedEventStart:开始加载DOM资源的时间
- domContentLoadedEventEnd:页面所有需要执行的脚本执行完成的时间,这个时间DOM已经ready
- domComplete: DOM结构生成的时间
- loadEventStart:onload事件执行开始的时间
- loadEventEnd:onload事件执行结束的时间
Performance
Performance下边一共有6项指标,分别是:
- FCP(First Contentful Pain)
- TTI(Time to interactive)
- SI(Speed Index)
- TBT(Total Blocking Time)
- LCP(Largest Contentful Paint)
- CLS(Cumulative Layout Shift)
这6个指标按照不同的权重进行计算,最终得到performance的分数,目前V8对于这几项的权重如下:
Audit | Weight |
---|---|
First Contentful Paint | 10% |
Speed Index | 10% |
Largest Contentful Paint | 25% |
Time to Interactive | 10% |
Total Blocking Time | 30% |
Cumulative Layout Shift | 15% |
当然,这个分数很多时候有人会问:“昨天我还是80分,今天怎么就60分了”,其实这是非常正常,因为我们在测试性能的时候会受到各种因素影响,目前来看,我遇到的请跨过基本都是网络状态导致的。官方也给出了几个常见的原因:
- A/B tests or changes in ads being served
- Internet traffic routing changes
- Testing on different devices, such as a high-performance
- desktop and a low-performance laptop
- Browser extensions that inject JavaScript and add/modify network requests
- Antivirus software
FCP(First Contentful Pain)
这个可能很多人并不陌生,这个其实就是很多时候我们用来计算白屏时间的方式。FCP其实就是页面出现第一个DOM所需的时间。图片、非白的canvas、SVG都被视为DOM内容。当然iframe内的任何元素都不会被计算。
FCP time(s) | Color-coding |
---|---|
0–1.8 | Green (fast) |
1.8–3 | Orange (moderate) |
Over 3 | Red (slow) |
那知道含义我们如何解决就清晰了,官方还特别提醒我们有时候我们使用字体,会非常影响FCP,我们应该首先让文本先出现。
如果我们自己手动计算的话可以这么来:responseEnd-fetchStart
TTI(Time to interactive)
这个用的人就相对少了,他指的是页面需要多长时间才能进行完全交互,完全交互指的是:
- FCP完成之后
- 大部分的DOM已经绑定好事件
- 50ms内响应用户的交互
这个可能有些不太好理解,什么情况算是大部分的DOM已经绑定好了事件?其实这个谷歌团队也是在不断的优化中,并且为了方便计算将FMP替换成了FCP。
第一次FI定义
经典的正向搜索,寻找一个5s内只有不超过50ms的任务。
第二次FI定义
之前定义的5s其实说服力不大,因为很多脚本可能还在加载中,越是距离FMP越近,可靠度必然越高。因此考虑延长时间范围来验证关键js都已经执行了。如图距离FMP之后的15s,有一个3秒的空白区域这是一个足够好的信号。
因此在第二次定义中,我们的5s不再是一个固定的值,而是距离FMP15s时,以3s的速度下降,但是不会低于1s。
f(∞)= 1,定义的是:距离FMP越远,我们截取的时间越短,但是这个范围不会降到1s以下。
f(t)=4*e^(-0.045*t)+1。
第三次FI定义
当页面执行最关键的与加载相关的任务时,长任务通常是密集的。如图中FMP到firstinteractive的范围,就是相对密集的。孤立的任务通常是一些第三方广告或分析脚本,这些任务不应该阻止第一次交互。
如果可以将一组长任务封装在小于250ms的区域L中,这样就不会有与[L.start-1s,L.start]
和[L.end,L.end+1s]
区域重叠的长任务,那么我们将它们称为孤立任务。
当然第三次定义认为FMP之后的5秒内是没有孤立任务的,原因是所有接近FMP的任务都有很高的临界概率。
第四次FI定义
这一次定义其实就是结合了第二次定义和第三次定义,从FMP之后的5s范围的固定值,变成了一个变量。
TTI time(s) | Color-coding |
---|---|
0–3.8 | Green (fast) |
3.9–7.3 | Orange (moderate) |
Over 7.3 | Red (slow) |
如何提高TTI的分数?我觉得可以把一些优先级不高的JS延迟执行,对脚本进行拆包等等。
SI(Speed Index)
这个大家可以作为参考即可,它衡量页面内容在视觉上的显示速度。捕获浏览器中页面加载的视频,并计算帧之间的视觉进展。通过比较当前帧和最终帧之间的距离来计算视觉进度。它是基于 Speedline Node.js 模块进行计算的。
SI time(s) | Color-coding |
---|---|
0–3.4 | Green (fast) |
3.4–5.8 | Orange (moderate) |
Over 5.8 | Red (slow) |
那知道含义我们如何解决就清晰了,大家可以参考Opportunities列出来的信息参考,主要就是:
- 最小化主线程工作
- 减少 JavaScript 执行时间
- 确保文本在 webFont 加载期间保持可见
TBT(Total Blocking Time)
TBT 测量页面被阻止响应用户交互(例如鼠标点击、屏幕点击或键盘按下)的总时间。总和是通过在FCP和TTI之间添加所有长任务的阻塞部分来计算的。具体的可以看看TTI中的FI定义这个在之前任何执行时间超过 50ms 的任务都是长任务。50ms后的时间量是阻塞部分。例如,检测到一个 70ms的任务,则阻塞部分将为 20 毫秒。
TBT time(ms) | Color-coding |
---|---|
0–200 | Green (fast) |
200–600 | Orange (moderate) |
Over 600 | Red (slow) |
那知道含义我们如何解决就清晰了,大家可以参考报告中的Opportunities列出来的信息参考,主要优化也是:
- 最小化主线程工作
- 减少 JavaScript 执行时间
- 确保文本在 webfont 加载期间保持可见
LCP(Largest Contentful Paint)
LCP 测量视口中最大的内容元素何时呈现到屏幕上。LCP报告的元素大小通常是用户在视口内可见的大小。如果元素延伸到视口之外,或者任何元素被剪裁或具有不可见的溢出,比如overflow
, 则这些部分不计入元素的大小,假如开发者用了min-width
那就会用这个大小记录。会被LCP检测的范围如下:
<img>
<svg>
中的<image>
<video>
元素(使用海报图片)- 具有通过该url()函数加载的背景图像的元素(与CSS 渐变相反)
- 含文本节点或者内联子元素的块级元素。
大家可以看看下边的例图:
在第二个示例中,布局更改并且以前最大的内容从视口中删除
LCP time(s) | Color-coding |
---|---|
0–2.5 | Green (fast) |
2.5–4 | Orange (moderate) |
Over 4 | Red (slow) |
CLS(Cumulative Layout Shift)
CLS 是衡量页面整个生命周期内发生的每个意外布局偏移的最大布局偏移分数的度量。一般资源是异步加载,或者 DOM 元素被动态添加到现有内容上方导致之前的元素变成了不稳定元素。
一系列的布局转换被称为会话窗口,指的是一个或多个单独的布局转换快速连续的发生,每次转换之间的时间小于1 秒,整个窗口持续时间最多为 5 秒。
单个偏移分数计算的方法:layout shift score = impact fraction * distance fraction
什么是impact fraction
如图,有一个元素在一帧中占据了视口的50%。然后,在下一帧中,元素向下移动视口高度的 25%。红色虚线矩形表示两个帧中元素可见区域的联合,在本例中,占总视口的 75%,因此其impact fraction为0.75。
什么是distance fraction
如图,元素移动了视口高度的 25%,那么distance fraction为 0.25。
现在,大家可以思考一下下边这图该怎么算。提示:绿框在灰框内
我们可以这么去降低CLS:
- 不要更改height和width属性,而是使用transform: scale()。
- 避免改变top,right,bottom,或left属性,并使用transform: translate()来代替。
CLS time(s) | Color-coding |
---|---|
0–0.1 | Green (fast) |
0.11–0.24 | Orange (moderate) |
Over 0.25 | Red (slow) |