衡量一个网站的好坏,所使用的指标很多,而且各有不同。
所以Google推出了 Web Vitals, 定义了指标集,旨在简化和统一衡量网站质量的指标。
在Web Vitals 指标中,Core Web Vitals 是其中最核心的部分,包含三个指标:
根据页面开始加载的时间报告可视区域内可见的最大图像或文本块完成渲染的计算时间,用于测验加载性能,衡量网站初次载入速度。 我们应该控制该值在2.5 秒
以内
最大其实就是指元素的尺寸大小,这个大小不包括可视区域之外或者是被裁剪的不可见的溢出。也不包括元素的Margin / Padding / Border等。
计算包括在内的元素有:
img 标签元素
内嵌在元素内的
元素
video 标签元素的封面元素
通过 url() 函数加载的带有背景图像的元素
包含文字节点的块级元素 或 行内元素
一般网页是分批加载的,因此所谓最大元素也是随着时间变化的,浏览器在在绘制第一帧时分发一个largest-contentful-paint
类型PerformanceEntry对象,随着时间的渲染,当有更大的元素渲染完成时,就会有另一个PerformanceEntry对象报告。
利用 PerformanceObserver 构造函数创建一个性能检测对象,可以通过以下代码打印采集数据:
let observer = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
});
observer.observe({ type: "largest-contentful-paint", buffered: true });
一般来说,通过上面的代码,最新的largest-contentful-paint条目的startTime就是LCP值。
首次输入延迟时间,主要为了测量页面加载期间响应度,测量交互性
。为了提供良好的用户体验,页面的 FID 应为100 毫秒
或更短。
测量用户第一次与页面交互(单击链接、点按按钮等等)到浏览器对交互作出响应,并实际能够开始处理事件处理程序所经过的时间。FID只关注不连续操作对应的输入事件,例如点击,轻触,按键等。一般只考虑测量首次输入的延迟。FID只考虑事件处理过程的延迟,不考虑事件处理花费的时间或者事件处理完成更新页面花费的时间。
和上面类似,创建PerformanceObserver对象监听 first-input 类型的条目,并获取条目的startTime和processingStart时间戳的差值作为结果
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});
累积布局偏移,测量视觉稳定性。为了提供良好的用户体验,页面的 CLS 应保持在 0.1. 或更少。
CLS是测量整个页面生命周期内发生的所有意外布局偏移中最大一连串的布局偏移分数。
每当一个可见元素从一个已渲染帧变更到另一个已渲染帧时,就是发生了布局偏移。
所谓一连串布局偏移,是指一个或者多个的布局偏移,这些偏移相隔少于1秒,总持续时间最大为5秒。
而最大一连串就是所有的一连串布局偏移中偏移累计分数最大的一连串。
具体这个分数是怎么算的呢,首先偏移前后的两个已渲染帧的总的叠加大小(只算可视区域内,重合部分只算一次),占可视区域的百分比,称为影响分数,例如有个元素一开始占可视区域的50%,然后下一帧往下偏移可视区域的25%,那么这个元素的影响分数就是0.75。然后取不稳定元素在一帧中的最大偏移距离(水平或垂直取最大)占对应可视区域(取水平对应宽度,垂直对应高度)的比例,称为距离分数,例如刚刚的例子,距离分数就是0.25。
距离分数和影响分数相乘就是偏移分数(例如上面例子相乘就是0.75 * 0.25 = 0.1875)。
常见的影响CLS分数的有
值得一提的是,布局偏移并不都是不好的,更改元素的起始位置是网页应用用常见的事。布局偏移只有在用户不期望其发生的才是不好的。比如用户自己发起的布局偏移就是没有问题,这些CLS不计算在内,CLS计算的是意外的布局偏移。在用户交互 500 毫秒内发生的布局偏移会带有hadRecentInput
标志,CLS计算会把这些偏移在计算中排除。
js测量CLS的原理是,创建一个PerformanceObserver对象来侦听意外偏移layout-shift
条目
let clsValue = 0;
let clsEntries = [];
let sessionValue = 0;
let sessionEntries = [];
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// 只将不带有最近用户输入标志的布局偏移计算在内。
if (!entry.hadRecentInput) {
const firstSessionEntry = sessionEntries[0];
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
// 如果条目与上一条目的相隔时间小于 1 秒且
// 与会话中第一个条目的相隔时间小于 5 秒,那么将条目
// 包含在当前会话中。否则,开始一个新会话。
if (sessionValue &&
entry.startTime - lastSessionEntry.startTime < 1000 &&
entry.startTime - firstSessionEntry.startTime < 5000) {
sessionValue += entry.value;
sessionEntries.push(entry);
} else {
sessionValue = entry.value;
sessionEntries = [entry];
}
// 如果当前会话值大于当前 CLS 值,
// 那么更新 CLS 及其相关条目。
if (sessionValue > clsValue) {
clsValue = sessionValue;
clsEntries = sessionEntries;
// 将更新值(及其条目)记录在控制台中。
console.log('CLS:', clsValue, clsEntries)
}
}
}
}).observe({type: 'layout-shift', buffered: true});
上面介绍了三个核心指标简单的js测量代码,但是现实情况往往要复杂许多,例如要考虑页面通过往返缓存恢复时,API不会报告指标相关的条目,而且API不考虑iframe的元素的问题等等。
在特殊复杂的页面中,单纯用这种检查方式,结果往往不准。
所以我们可以使用一些第三库,它已经帮我们把复杂的处理做了,例如使用官方的 web-vitals 库
npm install web-vitals
用法
import { getLCP, getFID, getCLS } from 'web-vitals'
getCLS((metric) => console.log('cls: ' + metric.value))
getFID((metric) => console.log('fid: ' + metric.value))
getLCP((metric) => console.log('lcp: ' + metric.value))
除了以上的Web Vitals 核心关键指标之外,还有其他的一些重要指标,例如
TTFB(Time to First Byte)
FCP(First Contentful Paint)
FP(First Paint)
SI(Speed Index)
TTI(Time to Interactive)
TBT(Total Blocking Time)
首包时间,资源请求到获取第一个字节之间的时间,包括以下阶段的总和
计算方式为:
console.log(
'TTFB:' +
(performance.timing.responseStart - performance.timing.navigationStart)
)
也可以用 PerformanceObserver 采集
new PerformanceObserver((entryList) => {
const [pageNav] = entryList.getEntriesByType('navigation')
console.log(`TTFB: ${pageNav.responseStart}`)
}).observe({
type: 'navigation',
buffered: true,
})
或者用 web-vitals 库
import {getTTFB} from 'web-vitals';
// 当 TTFB 可用时立即进行测量和记录。
getTTFB(console.log);
首屏时间,首次内容绘制的时间,指页面从开始加载到页面内容的任何部分在屏幕上完成渲染的时间。
计算方式
console.log(
"FCP:" +
performance.getEntriesByName("first-contentful-paint")[0].startTime
);
上面代码可能不好确定调用时机,可以采用 PerformanceObserver 来监听采集
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
console.log('FCP candidate:', entry.startTime, entry)
}
}).observe({ type: 'paint', buffered: true })
或者用 web-vitals 库
import {getFCP} from 'web-vitals';
// 当 FCP 可用时立即进行测量和记录。
getFCP(console.log);
白屏时间,首次渲染的时间点。FP和FCP有点像,但FP一定先于FCP发生,例如一个页面加载时,第一个DOM还没绘制完成,但是可能这时页面的背景颜色已经出来了,这时FP指标就被记录下来了。而FCP会在页面绘制完第一个 DOM 内容后记录。
计算方式
console.log(
"FP:" + performance.getEntriesByName("first-paint")[0].startTime
);
上面代码可能不好确定调用时机,可以采用 PerformanceObserver 来监听采集
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntriesByName("first-paint")) {
console.log("FP:", entry.startTime, entry);
}
}).observe({ type: "paint", buffered: true });
速度指数衡量页面加载期间内容的视觉显示速度,也就是页面填充快慢的指标。
良好的SI应该控制在3.4以内。
可交互时间,指标测量页面从开始加载到主要子资源完成渲染,并能够快速、可靠地响应用户输入所需的时间。
良好的TTI应该控制在5秒以内。
总阻塞时间,也就是从FCP到TTI之间的时间。
像上面提到 SI、TTI、TBT 指标想通过代码来测量是比较困难的,测量出来也是不准的。
所以我们一般需要借助一些性能测试工具。
Lighthouse是谷歌官方开发的性能分析工具是,直接在chrome应用商店内搜索然后安装扩展就行了(需要),国内则从极简插件
搜索。
点击Generate report 就可以看到性能报告。
报告会包含 FCP、TTI、SI、TBT、LCP、CLS 六个指标数据,但是无法测试FID。
还有总的性能评分,以及SEO的分数和一些其他的优化建议等等,总的来说报告数据算是很齐全的。
https://pagespeed.web.dev/?utm_source=psi&utm_medium=redirect(需要科学上网)
这是一个输入网址就可以测试性能的网站,基本该有的指标数据都有,包括Lighthouse暂不支持的FID。
https://www.webpagetest.org/ (需要科学上网)
同样是一个输入网址就可以测试性能的网站。
可以选择全球各地进行性能测试,同样提供详细的检查结果报告,包括清晰的瀑布图数据,以及相关的优化建议。
有个问题就是这个网站测试要排队,往往要等一会才出结果。
文章出处:https://juejin.cn/post/7076455229377478692#heading-20