跳到主要内容

采集指标

2024年04月22日
柏拉文
越努力,越幸运

一、认识


以用户为中心的效果指标是一项重要的工具,可帮助您了解和改善网站的体验,让真实用户受益。目前 Google 定义了FCPLCPCLS 等体验指标,已经成为了目前业界的标准。对于用户体验来说,指标可以简单归纳为加载速度视觉稳定交互延迟等几个方面:

  1. FP (First Paint)

  2. FCP (First Contentful Paint)

  3. FMP (First Meaning Paint)

  4. LCPLargest Contentful Paint

  5. FID (First Input Delay)

  6. CLS (Cumulative Layout Shift)

  7. NT (Navigation Timing)

  8. RF (Resource Flow)

本地通过 lighthouse 进行性能分析时, 会使用 6 大指标: FCPLCPSITTITBTCLS。这些指标涵盖了页面渲染、交互和视觉稳定性情况。

二、FP


2.1 认识

FP (First Paint) 表示页面开始首次绘制的时间点, 值越小约好。在 FP 时间点之前,用户看到的是导航之前的页面。

FP (First Paint) 首次非网页背景像素渲染, 从页面首次开始加载的时间点到页面视觉首次发生变化的时间点的时间段, 可以被视为白屏时间。比如设置的body背景色, FP不包含默认背景绘制,但包含非默认的背景绘制。假如,我给单页面应用的 body 元素加了一个背景色,那么FP记录的时间就是开始绘制带背景色的body的时间点,

2.2 计算

new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntriesByName('first-paint')) {
console.log('fp', entry);
}
}).observe({ type: 'paint', buffered: true });

三、FCP


3.1 认识

FCP (First Contentful Paint) 首次内容渲染, lighthouse 面板的六大指标之一, 表示首次绘制任何文本、图像、非空白 canvas 或者 SVG 的时间点,值越小约好

FCP (First Contentful Paint) 首次内容渲染, 从页面首次开始加载的时间点到到首次任何文本、图像、非空白canvas或者SVG完成渲染的时间点的时间段,可以被视为灰屏时间。 FCP是首次绘制有效内容的时间点, 所以FP会等于或者先于FCP。假如,我给单页面应用的 body 元素加了一个背景色,那么FP记录的时间就是开始绘制带背景色的body的时间点,而FCP记录的则是 body 生成之后,首次绘制来自DOM的有效内容的时间点,这个时候FP的时间点就先于FCP

3.2 计算

通过 PerformanceObserver API 获取如下:

new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
console.log('fcp', entry);
}
}).observe({ type: 'paint', buffered: true });

通过 Googleweb-vitals 获取如下:

import { getFCP } from 'web-vitals';
// 当 FCP 可用时立即进行测量和记录。
getFCP(console.log);

四、FMP


4.1 认识

FMP (First Meaning Paint) 首次有效绘制, 首次完成有意义内容绘制的时间点。值越小越好。是一个已经废弃的性能指标。在实践过程中,由于 FMP 对页面加载的微小差异过于敏感,经常会出现结果不一致的情况。此外,该指标的定义依赖于特定于浏览器的实现细节,这意味着它不能标准化,也不能在所有 Web 浏览器中实现。目前,官方并没有提供有效的获取 FMP 的接口,因此性能分析的时候不再使用这个指标。

FMP (First Meaning Paint) 首次有效绘制, 从页面首次开始加载的时间点到页面中增量最大的元素渲染完成的时间点的时间段, 为 FMP 时间点, 也可以被视为首屏渲染时间。因为元素增量最大的时候,页面主要内容也就一般都渲染完成了。

4.2 计算

思路

  1. 侦听页面元素的变化

  2. 遍历每次新增的元素,并计算这些元素的得分总和

  3. 如果元素可见,得分为 1 * weight(权重), 如果元素不可见,得分为0

如果每次都去遍历新增元素并计算是否可见是非常消耗性能的。实际上采用的是深度优先算法,如果子元素可见,那父元素可见,不再计算。 同样的,如果最后一个元素可见,那前面的兄弟元素也可见。通过深度优先算法,性能有了大幅的提升。

实现

export const initFMP = (): void => {
new MutationObserver((records: Array<MutationRecord>) => {
// 对当前的 document 进行计算评分
// 或者对 records.addedNodes的每个 node 元素,计算评分累加;每次遍历元素还需要判断此元素是否在可视区域
}).observe(document, { childList: true, subtree: true });
};

五、LCP


5.1 认识

LCPLargest Contentful Paint)视口中可见最大图片或者文本块的渲染时间 lighthouse 面板中的六大指标之一,完成最大内容绘制的时间点,值越小约好。

LCPLargest Contentful Paint)最大内容绘制, 从页面首次开始加载的时间点到可视区域内最大的图像或者文本块完成渲染的时间点的时间段。是一个以用户为中心的性能指标,可以测试用户主观感知到的页面加载速度,因为最大内容绘制完成时,往往可以认为页面将要加载完成。通常来说,为了提供良好的用户体验,我们应该努力将 最大内容绘制控(LCP) 制在2.5秒或以内

5.2 计算

通过 PerformanceObserver API 获取如下:

new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const entry = entries[entries.length - 1];
console.log('lcp', entry);
}).observe({ type: 'largest-contentful-paint', buffered: true });

通过 Googleweb-vitals 获取如下:

import { getLCP } from 'web-vitals';
// 当 LCP 可用时立即进行测量和记录。
getLCP(console.log);

六、FID


6.1 认识

FID (First Input Delay) 首次输入延迟, FID 是从用户第一次与页面交互(例如当他们单击链接、点按按钮或使用由 JavaScript 驱动的自定义控件)直到浏览器对交互作出响应,并实际能够开始处理事件处理程序所经过的时间。通常来说,我们可以认为,FID 时间在 100ms 内的能 让用户得到良好的使用体验

6.2 计算

通过 PerformanceObserver API 获取如下:

new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const entry = entries[entries.length - 1];
const delay = entry.processingStart - entry.startTime;
console.log('FID:', delay, entry);
}).observe({ type: 'first-input', buffered: true });

通过 Googleweb-vitals 获取如下:

import { getFID } from 'web-vitals';
// 当 FID 可用时立即进行测量和记录。
getFID(console.log);

七、CLS


7.1 认识

CLS (Cumulative Layout Shift) 累计布局偏移, CLS 是测量整个页面生命周期(页面可见性变成隐藏)内发生的所有 外布局偏移 中最大一的 布局偏移分数。每当一个已渲染的可见元素的位置从一个可见位置变更到下一个可见位置时,就发生了布局偏移 。CLS 会衡量在网页的整个生命周期内发生的所有意外布局偏移的得分总和。通常来说,我们应该将 CLS 分数控制在 0.1 或以下

7.2 计算

通过 PerformanceObserver API 获取如下:

let clsValue = 0;
let clsEntries = [];

let sessionValue = 0;
let sessionEntries: Array<LayoutShift> = [];

new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
entries.forEach((entry)=>{
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;

// 记录 CLS 到 Map 里
const metrics = {
entry,
clsValue,
clsEntries,
} as IMetrics;
this.metrics.set(metricsName.CLS, metrics);
}
}
});
}).observe({ type: '', buffered: true });

通过 Googleweb-vitals 获取如下:

import {getCLS} from 'web-vitals';
// 在所有需要汇报 CLS 的情况下
// 对其进行测量和记录。
getCLS(console.log);

八、NT


8.1 认识

NT (Navigation Timing)

8.2 计算

九、RF


我们可以获取每次加载时所访问的静态资源,将收集到的静态资源做成瀑图等分析图形,来找出导致静态资源加载时间过长的问题所在。

9.1 认识

RF (Resource Flow)

9.2 计算

const resource = performance.getEntriesByType('resource')
const formatResourceArray = resource.map(item => {
return {
name: item.name, //资源地址
startTime: item.startTime, //开始时间
responseEnd: item.responseEnd, //结束时间
time: item.duration, //消耗时间
initiatorType: item.initiatorType, //资源类型
transferSize: item.transferSize, //传输大小
//请求响应耗时 ttfb = item.responseStart - item.startTime
//内容下载耗时 tran = item.responseEnd - item.responseStart
//但是受到跨域资源影响。除非资源设置允许获取timing
};
});

十、TTI


TTI(time to ineractive) 首次可交互时间, lighthouse 面板中的六大指标之一, 用于测量页面从开始加载到主要资源完成渲染,并能够快速、可靠地响应用户输入所需的时间, 值越小约好。和 FMPSI 一样,官方并没有提供获取 TTI 的有效接口,只能通过 lighthouse 面板来查看,不会作为 Sentry 做性能分析的指标。

十一、TBT


TBT(total blocking time) 阻塞总时间, lighthouse 面板中的六大指标之一,用于测量 FCPTTI 之间的总的阻塞时间,值越小约好。和 TTI 一样,官方也没有提供获取 TBT 的有效接口,只能通过 lighthouse 面板来查看,不会作为 Sentry 做性能分析的指标。

十二、MPFID


MPFID (Max Potential First Input Delay) 最大潜在首次输入延迟,用于测量用户可能遇到的最坏情况的首次输入延迟。和 FMP 一样,这个指标已经被废弃不再使用。

十三、Long Task


13.1 认识

Long Task 衡量用户在使用过程中遇到的交互延迟、阻塞情况。这个指标,可以告诉我们哪些任务执行耗费了 50ms 或更多时间

13.2 计算

new PerformanceObserver(function(list) {
var perfEntries = list.getEntries();
for (var i = 0; i < perfEntries.length; i++) {
...
}
})observe({ type: 'longtask'});

十四、SI


SI (Speed Index) lighthouse 面板中的六大指标之一,用于衡量页面加载期间内容的绘制速度,值越小约好。SIFMP 一样,官方也没有提供有效的获取接口,只能通过 lighthouse 面板来查看,不作为 Sentry 等工具做性能分析的指标。

十五、Memory


performance.memory 可以显示此刻内存占用情况,它是一个动态值,其中:

  • jsHeapSizeLimit: 该属性代表的含义是:内存大小的限制

  • totalJSHeapSize: 表示总内存的大小

  • usedJSHeapSize: 表示可使用的内存的大小

通常,usedJSHeapSize 不能大于 totalJSHeapSize,如果大于,有可能出现了内存泄漏

// load事件中获取此时页面的内存大小
window.addEventListener('load', () => {
console.log('memory', performance.memory);
});

参考资料


Largest Contentful Paint (LCP)

性能优化