前端性能指标

FCP、LCP、TTI、CLS、FID 等 Web Vitals 指标的含义与测量

问题

解释前端性能优化中的关键指标:FCP、LCP、TTI、CLS、FID,以及如何测量它们。

解答

指标概览

指标全称含义良好标准
FCPFirst Contentful Paint首次内容绘制< 1.8s
LCPLargest Contentful Paint最大内容绘制< 2.5s
FIDFirst Input Delay首次输入延迟< 100ms
CLSCumulative Layout Shift累积布局偏移< 0.1
TTITime to Interactive可交互时间< 3.8s

1. FCP(首次内容绘制)

页面首次渲染出任何文本、图片、非空白 canvas 或 SVG 的时间。

// 使用 Performance API 获取 FCP
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.name === 'first-contentful-paint') {
      console.log('FCP:', entry.startTime, 'ms');
    }
  }
});

observer.observe({ type: 'paint', buffered: true });

2. LCP(最大内容绘制)

视口内最大的图片、文本块或视频渲染完成的时间。这是 Core Web Vitals 的核心指标。

// 监听 LCP
const lcpObserver = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  // 取最后一个,因为 LCP 可能会更新
  const lastEntry = entries[entries.length - 1];
  console.log('LCP:', lastEntry.startTime, 'ms');
  console.log('LCP 元素:', lastEntry.element);
});

lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });

3. FID(首次输入延迟)

用户首次与页面交互(点击、触摸、按键)到浏览器响应的延迟时间。

// 监听 FID
const fidObserver = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // processingStart - startTime = 输入延迟
    const delay = entry.processingStart - entry.startTime;
    console.log('FID:', delay, 'ms');
  }
});

fidObserver.observe({ type: 'first-input', buffered: true });

注意:FID 已被 INP(Interaction to Next Paint)取代,成为新的 Core Web Vitals 指标。

4. CLS(累积布局偏移)

页面生命周期内所有意外布局偏移的累积分数。

// 监听 CLS
let clsValue = 0;

const clsObserver = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // 只计算非用户输入导致的偏移
    if (!entry.hadRecentInput) {
      clsValue += entry.value;
      console.log('当前 CLS:', clsValue);
    }
  }
});

clsObserver.observe({ type: 'layout-shift', buffered: true });

5. TTI(可交互时间)

页面完全可交互的时间点,需满足:

  • 已触发 FCP
  • 事件处理器已注册
  • 页面在 5 秒内响应用户交互
// TTI 没有直接的 API,可以使用 Google 的 tti-polyfill
// 或通过 Lighthouse 测量

// 简化版本:监听 load 事件后的长任务
const ttiObserver = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // 长任务(>50ms)会阻塞交互
    console.log('长任务:', entry.duration, 'ms');
  }
});

ttiObserver.observe({ type: 'longtask', buffered: true });

使用 web-vitals 库

Google 提供了官方库简化测量:

import { onFCP, onLCP, onFID, onCLS, onINP } from 'web-vitals';

// 收集所有指标
onFCP(console.log);
onLCP(console.log);
onFID(console.log);
onCLS(console.log);
onINP(console.log); // FID 的替代指标

// 上报到分析服务
function sendToAnalytics(metric) {
  const body = JSON.stringify({
    name: metric.name,
    value: metric.value,
    id: metric.id,
  });
  
  // 使用 sendBeacon 确保页面卸载时也能发送
  navigator.sendBeacon('/analytics', body);
}

onLCP(sendToAnalytics);
onCLS(sendToAnalytics);
onINP(sendToAnalytics);

优化方向

指标优化方法
FCP减少阻塞渲染的资源、内联关键 CSS、预加载字体
LCP优化图片加载、预加载 LCP 元素、使用 CDN
FID/INP拆分长任务、延迟非关键 JS、使用 Web Worker
CLS为图片/视频设置尺寸、避免动态插入内容、使用 hd18w 动画
TTI代码分割、延迟加载、减少主线程工作

关键点

  • Core Web Vitals 包含 LCP、CLS、INP 三个指标,是 Google 搜索排名因素
  • FCP 反映首屏速度,LCP 反映主要内容加载速度
  • CLS 衡量视觉稳定性,为图片设置宽高是最简单的优化
  • FID/INP 衡量交互响应,长任务(>50ms)是主要影响因素
  • 使用 web-vitals 库 + sendBeacon 进行真实用户监控(RUM)