Skip to content

常见前端性能指标

前端性能指标是衡量网站用户体验的重要标准,直接影响用户满意度、SEO 排名和业务转化率。本文将详细介绍各种前端性能指标,帮助开发者理解和优化网站性能。

一、Core Web Vitals 核心指标

Google 在 2020 年推出的 Core Web Vitals 是衡量网站用户体验的三个核心指标,也是 SEO 排名的重要因素。

1. LCP (Largest Contentful Paint) 最大内容绘制

LCP 是指网页在加载过程中,视口(viewport)内最大内容元素渲染完成的时间点

  • “最大内容元素”通常是:
    • 图片(<img>background-image
    • 视频的海报帧
    • 块级文本元素(<p><h1> 等)
  • 浏览器会:
    • 追踪视口中最大的内容元素。
    • 记录它完全渲染的时间(例如,图片加载完成或文本绘制完成)。
    • 如果稍后出现一个更大的元素(例如,滚动后加载了一张新图片),LCP 会被更新。

也就是说,LCP 衡量用户在视觉上感觉页面“主要内容”加载完成的速度

LCP 的性能标准

  • 优秀(Good): ≤ 2.5 秒
  • 需要改进(Needs Improvement):2.5 - 4 秒
  • 差(Poor): > 4 秒

如何测量 LCP

  • LCP 可以通过 Performance APILargestContentfulPaint 条目捕获。浏览器会持续追踪视口中最大的内容元素,并记录其渲染时间。
js
// 创建一个 PerformanceObserver 实例来监听性能事件
const observer = new PerformanceObserver((entryList) => {
  // getEntries() 返回一个性能条目数组
  const entries = entryList.getEntries();
  for (const entry of entries) {
    // entry.startTime 是 LCP 时间
    console.log(`最大内容绘制 (LCP): ${entry.startTime.toFixed(2)}ms`);
    // entry.element 是触发 LCP 的 DOM 元素
    console.log('LCP 元素:', entry.element);
  }
});

// 开始监听 'largest-contentful-paint' 类型的事件
// buffered: true 确保在观察者创建之前发生的事件也能被捕获
observer.observe({ type: 'largest-contentful-paint', buffered: true });
  • 也可以在 Chrome DevTools 的 Performance 面板中查看 LCP。打开 DevTools (F12),转到 "Performance" 标签页,录制页面加载过程,LCP 会在时间线上被明确标记出来。

LCP 的常见影响因素

  • 慢的服务器响应:服务器延迟高 → HTML 获取慢 → 资源加载延迟。

  • 渲染阻塞资源:例如大体积的 CSS、JS 阻塞页面渲染。

  • 图片和视频加载慢:首屏大图过大,未使用懒加载/压缩。

  • 前端渲染策略问题:CSR(客户端渲染)比 SSR(服务端渲染)更慢,可能影响首屏 LCP。

优化 LCP 的方法

  • 服务器层面优化:使用 CDN、缓存,降低 TTFB(首字节时间)。
  • 优化资源加载
    • 图片:压缩、WebP/AVIF 格式、懒加载、预加载首屏大图。
    • CSS/JS:减少阻塞,使用代码分割。
  • 优先渲染关键内容:SSR / SSG(Next.js、Nuxt.js),加快首屏直出。
  • 预加载关键资源<link rel="preload"> 用于提前加载首屏大图或字体。

2. FID (First Input Delay) 首次输入延迟

定义:用户首次与页面交互(点击、触摸、按键)到浏览器实际开始处理事件处理程序的时间。

评判标准

  • 良好:≤ 100 毫秒
  • 需要改进:100 - 300 毫秒
  • 差:> 300 毫秒

影响 FID 的因素

  • 主线程阻塞
  • JavaScript 执行时间过长
  • 大型第三方脚本

优化策略

js
// 代码分割,按需加载
import { heavyFunction } from './heavy-module.js';

// 使用 Web Workers 处理复杂计算
const worker = new Worker('calculation-worker.js');
worker.postMessage(data);

// 延迟非关键 JavaScript
<script defer src="non-critical.js"></script>;

3. CLS (Cumulative Layout Shift) 累积布局偏移

CLS 衡量的是网页在加载过程中,元素位置发生意外变化的稳定性

换句话说,它关注的是:

👉 页面在用户交互前,内容是否会乱跳?

比如:

  • 你在阅读文章时,突然广告加载进来,把文字往下挤。
  • 你准备点按钮,结果按钮被图片挤开了,你点到了别的东西。

这些情况都会增加 CLS 值

CLS 的计算方式

CLS 是所有单个布局偏移分数的总和,每个分数按以下方式计算:

偏移分数 = 影响因子 (Impact Fraction) × 距离因子 (Distance Fraction)

  • 影响因子:受偏移影响的视口区域比例。例如,一个元素从顶部移动到底部,可能会影响 50% 的视口。
  • 距离因子:元素移动的距离相对于视口高度(或宽度)的比例。例如,移动了视口高度的 10%,则距离因子为 0.1。

如何测量 CLS

  • CLS 是通过 LayoutShift 性能条目计算的。浏览器会追踪所有非用户交互触发的布局变化,并计算一个“偏移分数”。

    js
    let clsScore = 0;
    // 创建 PerformanceObserver 来监听布局偏移事件
    const observer = new PerformanceObserver((entryList) => {
      for (const entry of entryList.getEntries()) {
        // 忽略由用户输入(如点击、滚动)在 500ms 内触发的布局偏移
        if (!entry.hadRecentInput) {
          // entry.value 是单次布局偏移的分数
          clsScore += entry.value;
          console.log(`单次布局偏移分数: ${entry.value.toFixed(4)}`);
        }
      }
      // 累加所有分数得到最终的 CLS
      console.log(`累积布局偏移 (CLS): ${clsScore.toFixed(4)}`);
    });
    
    // 开始监听 'layout-shift' 类型的事件
    observer.observe({ type: 'layout-shift', buffered: true });
  • 根据 Google 的标准,CLS 分数低于 0.1 是理想的。你可以使用 Chrome DevTools 的 Performance 面板来可视化 CLS,发生偏移的元素会被高亮显示。

常见导致 CLS 的原因

  • 图片、广告、iframe 没有固定尺寸,高度或宽度后加载才撑开。
  • 动态插入的内容没有预留空间。
  • 使用了 FOIT/FOUT(字体加载闪动)。
  • 按钮、表单被动态元素挤开。

如何优化 CLS

  • 图片、视频、广告 设置固定宽高或使用 aspect-ratio
  • 为动态内容预留空间(骨架屏、占位符)。
  • 避免在 已有内容上方 插入新内容。
  • 使用 font-display: swap 避免字体闪动。
  • 慎用动画或过渡,避免引起大幅度位移。

二、传统性能指标

1. FP (First Paint) 首次绘制,页面开始呈现内容的时刻

First Paint (FP) 表示浏览器首次把任何像素绘制到屏幕上的时间点。它不一定是有意义的内容(可能只是背景色),但标志着用户看到“页面开始有东西出现”了。

如何测量 FP

  • FP 是第一个渲染里程碑,通常通过 Performance API 来捕获。它发生在浏览器解析完 DOM 和 CSSOM 并开始绘制像素时。以下是测量方法:

    js
    // 监听页面加载完成事件
    window.addEventListener('load', () => {
      // 使用 Performance API 获取所有“paint”类型的性能条目
      const performanceEntries = window.performance.getEntriesByType('paint');
    
      // 找到名为 'first-paint' 的条目
      const fpEntry = performanceEntries.find((entry) => entry.name === 'first-paint');
    
      if (fpEntry) {
        // fpEntry.startTime 是从页面导航开始到首次绘制发生的时间(毫秒)
        console.log(`首次绘制 (FP): ${fpEntry.startTime.toFixed(2)}ms`);
      } else {
        console.log('浏览器不支持 FP 或无法获取');
      }
    });

这段代码使用 performance.getEntriesByType('paint') 来获取与绘制相关的性能条目,找到 first-paint 条目并记录其 startTime (以毫秒为单位)。大多数现代浏览器(Chrome、Edge、Firefox)都支持此 API。

FP 代表什么

FP 标志着渲染的开始,表明浏览器已经开始工作。例如,背景颜色的变化或加载指示器的出现都会触发 FP。它通常发生在:

  • 浏览器解析 HTML <head> 并加载了 CSS。

  • 浏览器开始渲染第一个 DOM 元素(例如 <body> 的背景)。

FP 的局限性

FP 只追踪第一个像素的绘制,而不管内容是否有意义。例如,即使用户想看的文章或图片还未加载,一个背景色的变化也会触发 FP。这正是 FMPLCP 发挥作用的地方。

2. FCP (First Contentful Paint) 首次内容绘制

FCP 是核心网页性能指标之一,用于测量页面第一次渲染“有内容”的时刻

它标记了用户从打开页面开始,到首次看到非空白内容(文本、图片、SVG、canvas 等)出现在屏幕上的时间。

  • ⚠️ FCP ≠ 白屏结束时间,因为即使只出现一个小 logo 或一行字,也会记录为 FCP。。

FCP 测量范围

  • Good(良好): ≤ 1.8s
  • Needs Improvement(需要改进): 1.8s ~ 3.0s
  • Poor(较差): > 3.0s

FCP 的计算过程(浏览器角度)

  1. 用户输入 URL,浏览器开始加载资源。

  2. 解析 HTML → 构建 DOM 树。

  3. 下载并解析 CSS → 构建 CSSOM 树。

  4. DOM + CSSOM → 生成 Render Tree。

  5. 浏览器开始绘制第一个非空白内容(文字 / 图片 / svg / canvas)。

    👉 这个时刻就是 FCP

如何测量 FCP

  1. Lighthouse / PageSpeed Insights
    • 打开 Chrome DevToolsLighthouse → 生成报告 → FCP 会显示在性能指标里。
  2. FCP 可以通过 Performance API 中的 paint 条目捕获。浏览器在首次绘制“有意义内容”时会生成 "first-contentful-paint" 条目。
js
// 创建 PerformanceObserver 实例监听 paint 事件
const observer = new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (entry.name === 'first-contentful-paint') {
      // entry.startTime 就是 FCP 时间
      console.log(`首次内容绘制 (FCP): ${entry.startTime.toFixed(2)}ms`);
    }
  }
});

// 监听 paint 类型的性能事件
observer.observe({ type: 'paint', buffered: true });

如何优化 FCP

FCP 的本质是 尽快把首个内容绘制到屏幕,所以优化方向是:

  1. 减少关键资源阻塞

    • 压缩 HTML / CSS / JS,减少解析时间。
    • 避免在 <head> 放阻塞渲染的 JS(可以 defer / async)。
  2. 优化 CSS

    • 压缩 CSS 文件。
    • 使用关键 CSS(Critical CSS)优先渲染首屏内容。
  3. 首屏内容优先

    • 懒加载非首屏图片
    • 提前加载首屏关键图片(<link rel="preload">)。
  4. 使用 CDN / 缓存

    • 静态资源放在 CDN,减少网络延迟。
    • 利用浏览器缓存,加快二次访问。

3. TTI (Time to Interactive) 可交互时间

TTI 表示用户打开页面后,页面主要内容已经渲染完毕,并且能够快速响应点击、输入、滚动等操作的时间点。

换句话说:

  • 页面视觉上可能很快就显示出来了(比如 FPFCP 已经完成)。
  • 但是如果 JS 还在执行长任务(long task),用户点击按钮没有反应,那么还不能算“可交互”。
  • TTI 要等到 CPU 空闲,没有阻塞用户交互的大任务,才会被判定完成。

TTI计算方法(简化版)

  1. 页面加载后,浏览器开始绘制内容(FP/FCP)。
  2. 找到 最后一个长任务(>50ms)结束的时间点
  3. 在该点之后,页面要 保持至少 5 秒 CPU 相对空闲(无长任务),且网络请求稳定。
  4. 这个时间点就是 TTI。

优化 TTI 的方法

  1. 减少长任务 (long tasks)
    • 拆分大块 JS 逻辑,避免阻塞主线程。
    • 使用 requestIdleCallback、setTimeout 拆分执行。
  2. 代码分割 (Code Splitting)
    • 只加载首屏需要的 JS,其他的延迟或按需加载。
  3. 延迟非关键资源加载
    • 使用 defer/async 加载非核心 JS。
    • 懒加载图片、视频等资源。
  4. Web Worker
    • 把计算量大的任务丢到 Worker 线程,避免阻塞主线程。

举个例子:

  • 页面 2 秒时首屏显示出来(FCP)。
  • 但是 JS 逻辑还在加载和执行,按钮点击没反应。
  • 到 6 秒时,JS 执行完毕,主线程空闲,页面变得真正可交互。
  • 那么 TTI = 6s

4. TBT (Total Blocking Time) 总阻塞时间

TBT = 从 FCP(First Contentful Paint)到 TTI(Time to Interactive)之间,所有长任务的阻塞时间之和。

  • 长任务(Long Task):

    浏览器主线程上执行时间超过 50ms 的任务。

  • 阻塞时间:

    任务执行总时长 - 50ms。(比如一个 JS 执行了 120ms,那么阻塞时间 = 120 - 50 = 70ms)

为什么重要

  • TBT 可以反映用户在页面 还没完全可交互 时,点击/输入等操作会被延迟响应的程度。
  • FID(首次输入延迟) 相关,但 FID 依赖用户真实操作,而 TBT 可以在实验室环境(Lighthouse 等工具)下测得,因此是 FID 的实验室替代指标

优化方向

  1. 减少 JavaScript 执行时间

    • 代码拆分(Code Splitting)
    • 按需加载
    • 删除无用依赖
  2. 减少主线程长任务

    • 使用 Web Worker 处理复杂计算
    • 避免阻塞式同步操作
  3. 优化第三方脚本

    • 异步加载(async / defer)
    • 移除不必要的统计 / 广告脚本
  4. 优化渲染

    • 使用虚拟滚动、懒加载图片等

Released under the MIT License.