基本指标介绍
1. 首次绘制(First Paint,FP)
FP 是时间线上的第一个“时间点”,是指浏览器从响应用户输入网址地址,到浏览器开始显示内容的时间,简而言之就是浏览器第一次发生变化的时间。
2. 首次内容绘制(First Contentful Paint,FCP)
FCP(全称“First Contentful Paint”,翻译为“首次内容绘制”),是指浏览器从响应用户输入网络地址,在页面首次绘制文本,图片(包括背景图)、非白色的 canvas 或者 SVG 才算做 FCP,有些文章说 FCP 是首屏渲染事件,这其实是不对的。
3. 可交互时间(Time to Interactive,TTI)
TTI,翻译为“可交互时间”表示网页第一次完全达到可交互状态的时间点。可交互状态指的是页面上的 UI 组件是可以交互的(可以响应按钮的点击或在文本框输入文字等),不仅如此,此时主线程已经达到“流畅”的程度,主线程的任务均不超过 50 毫秒。在一般的管理系统中,TTI 是一个很重要的指标。
4. 最大内容绘制(Largest Contentful Paint,LCP)
LCP(全称“Largest Contentful Paint”)表示可视区“内容”最大的可见元素开始出现在屏幕上的时间点。
5. 首次有效绘制(First Meaning Paint, FMP) 废弃
FMP(全称“First Meaningful Paint”,翻译为“首次有效绘制”表示页面的“主要内容”开始出现在屏幕上的时间点,它以前是我们测量用户加载体验的主要指标。本质上是通过一个算法来猜测某个时间点可能是 FMP,但是最好的情况也只有 77%的准确率,在 lighthouse6.0 的时候废弃掉了这个指标,取而代之的是 LCP 这个指标。
performance 介绍
performance 对象是专门用来用于性能监控的对象,内置了一些前端需要的性能参数。
1. performance.now()方法
performance.now()
返回 performance.navigationStart
至当前的毫秒数。performance.navigationStart
是下文将介绍到的可以说是浏览器访问最初的时间测量点。
performance.now(); // 24614164.599999994
2. performance.timing
3. performance.getEntries()方法
浏览器获取网页时,会对网页中每一个对象(脚本文件、样式表、图片文件等等)发出一个 HTTP/HTTPS
请求。performance.getEntries()
方法以数组形式,返回一个 PerformanceEntry
列表,这些请求的时间统计信息,有多少个请求,返回数组就会有多少个成员。
指标计算方法
1. 首屏和白屏
白屏时间是指浏览器从响应用户输入网址地址,到浏览器开始显示内容的时间,一种比较简单的做法是在 body
标签之前获取当前时间 - performance.timing.navigationStart
,或者直接获取 performance
中关于 paint
的两个数据,都可以直接作为白屏数据,这两个数据一般差别不大。
首次绘制 FP
包括了任何用户自定义的背景绘制,它是首先将像素绘制到屏幕的时刻。
首次内容绘制 FCP
是浏览器将第一个 DOM
渲染到屏幕的时间。该指标报告了浏览器首次呈现任何文本、图像、画布或者 SVG
的时间。
也可以使用其他的计算方法:白屏时间 = 页面开始展示的时间点 - 开始请求的时间点。
2. TTI
关于 TTI 可以首先了解下谷歌提出的性能模型 RAIL:
- 响应:输入延迟时间(从点按到绘制)小于
100
毫秒。用户点按按钮(例如打开导航)。
- 动画:每个帧的工作(从
JS
到绘制)完成时间小于16
毫秒。用户滚动页面,拖动手指(例如,打开菜单)或看到动画。拖动时,应用的响应与手指位置有关(例如,拉动刷新、滑动轮播)。此指标仅适用于拖动的持续阶段,不适用于开始阶段。
- 空闲:主线程
JS
工作分成不大于50
毫秒的块。用户没有与页面交互,但主线程应足够用于处理下一个用户输入。
- 加载:页面可以在
1000
毫秒内就绪。用户加载页面并看到关键路径内容。
我们可以通过 domContentLoadedEventEnd
来粗略的进行估算:
TTI:domContentLoadedEventEnd - navigationStart
谷歌实验室也提供了更加便捷准确的 api
包进行测算 tti-polyfil
:
import ttiPolyfill from "./path/to/tti-polyfill.js";
ttiPolyfill.getFirstConsistentlyInteractive(opts).then((tti) => {
// Use `tti` value in some way.
});
3. LCP
在过去,我们也有推荐的性能指标,如:FMP (First Meaningful Paint)
和SI (Speed Index)
可以帮我们捕获更多的首次渲染之后的加载性能,但这些过于复杂,而且很难解释,也经常出错,没办法确定主要内容什么时候加载完。
根据
W3C Web
性能工作组的讨论和
所谓绘制面积可以理解为每个元素在屏幕上的 “占地面积” ,如果元素延伸到屏幕外,或者元素被裁切了一部分,被裁切的部分不算入在内,只有真正显示在屏幕里的才算数。图片元素的面积计算方式稍微有点不同,因为可以通过
CSS
将图片扩大或缩小显示,也就是说,图片有两个面积:“渲染面积”与“真实面积”。在LCP
的计算中,图片的绘制面积将获取较小的数值。例如:当“渲染面积”小于“真实面积”时,“绘制面积”为“渲染面积”,反之亦然。
页面在加载过程中,是线性的,元素是一个一个渲染到屏幕上的,而不是一瞬间全渲染到屏幕上,所以“渲染面积”最大的元素随时在发生变化。如果使用
PerformanceObserver
去捕获LCP
,会发现每当出现“渲染面积”更大的元素,就会捕获出一条新的性能条目。
如果元素被删除,
LCP
算法将不再考虑该元素,如果被删除的元素刚好是 “绘制面积” 最大的元素,则使用新的 “绘制面积” 最大的元素创建一个新的性能条目。
该过程将持续到用户第一次滚动页面或第一次用户输入(鼠标点击,键盘按键等),也就是说,一旦用户与页面开始产生交互,则停止报告新的性能条目。
可以直接使用 PerformanceObserver
来捕获 LCP
:
const observer = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
const lcp = lastEntry.renderTime || lastEntry.loadTime;
console.log("LCP:", lcp);
});
observer.observe({ entryTypes: ["largest-contentful-paint"] });
LCP
也不是完美的,也很容易出错,它会在用户进行交互后就停止捕获,可能会获取到错误的结果,如果有占据页面很大的轮播图也会产生问题会不断的更新 LCP
。
LCP
也有现成的计算工具库 web-vitals
:
import { getLCP } from "web-vitals";
// Measure and log the current LCP value,
// any time it's ready to be reported.
getLCP(console.log);