前端性能指标速查手册

前端性能指标速查手册

一、一张时间线先理清所有指标的位置

markdown 复制代码
用户点链接
    │
    ▼                                                   用户能交互
    ─────────────────────────────────────────────────────┐
    0              服务器返回  DOM解析完  最大内容出现     所有资源下完
    │                 │          │           │            │
    │ ←── TTFB ──→    │          │           │            │
    │                 │ ←─ DCL ─→│           │            │
    │        ←──── FP / FCP ────→│           │            │
    │        ←──────── LCP ─────────────────→│            │
    │        ←───────────────── Load ──────────────────→  │
    │        ←───────────────── TTI ──────────────────→   │
    ▼
导航开始(performance.timeOrigin 零点)

理解所有指标的第一件事:它们都用同一把尺子量(距离导航开始多少 ms),所以能直接比较、相减。


二、核心指标,按"谁先谁后"排列

1. TTFB · Time To First Byte

"服务器返回 HTML 第一个字节要多久"

  • 回答:网络 + 服务端 有没有问题
  • 包括:DNS 解析、TCP 握手、TLS 协商、服务端处理、HTML 开始返回
  • 看它发现什么:后端慢、CDN 配错、DNS 查询慢、HTTPS 握手慢

测量方式

js 复制代码
const nav = performance.getEntriesByType('navigation')[0];
const ttfb = nav.responseStart; // 从导航开始到收到第一个字节

达标线:< 200ms 好 / 200~600ms 可接受 / > 600ms 要改


2. FP · First Paint

"浏览器第一次往屏幕刷像素"(哪怕只是背景色)

  • 实用意义不大,因为画一个灰色背景也算 FP
  • 通常你会忽略它,直接看 FCP

3. FCP · First Contentful Paint(关键)

"浏览器第一次画出有意义的内容"(文本、图片、SVG、canvas 等)

  • 用户视角:"白屏结束了"
  • 被 Google 官方定义为 Core Web Vital 的"加载"维度之一
  • 注意:SPA 里 FCP 可能是 index.html 的 loading 骨架,而不是应用真正渲染

测量方式

js 复制代码
new PerformanceObserver((list) => {
  list.getEntries().forEach((e) => {
    if (e.name === 'first-contentful-paint') {
      console.log('FCP:', e.startTime);
    }
  });
}).observe({ type: 'paint', buffered: true });

达标线:< 1.8s 好 / 1.8~3s 可接受 / > 3s 差


4. DCL · DOMContentLoaded

"HTML 全部解析完 + 所有 defer / module script 执行完"

  • 不等图片、样式、iframe
  • 对 SPA 意义比传统页面小(SPA 的 DOM 大部分是 JS 构造的,不在 HTML 里)

测量方式

js 复制代码
nav.domContentLoadedEventEnd;

5. LCP · Largest Contentful Paint(Core Web Vital)

"页面主要视觉区域画完的时刻"(页面里最大的那个内容块)

  • 回答:用户觉得页面"差不多好了" 是什么时候
  • Google 三大 Core Web Vitals 之一,直接影响 SEO
  • 会随内容变大而不断更新,直到用户首次交互才定格
  • 比 FCP 更贴近真实用户体感

测量方式

js 复制代码
new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lcp = entries[entries.length - 1]; // 最后一次上报的才是最终 LCP
  console.log('LCP:', lcp.startTime, 'element:', lcp.element);
}).observe({ type: 'largest-contentful-paint', buffered: true });

达标线 :< 2.5s 好 / 2.5~4s 可接受 / > 4s 差(Google 硬标准)


6. Load

"HTML 声明的所有资源都下完"(含图、CSS、子 iframe)

  • 不等:动态 import、运行时 fetch、new Image
  • 在 SPA 里意义很小,常早于应用真正可用
  • 看它的主要用途:检查初始 bundle + 关键资源加载是否异常
js 复制代码
nav.loadEventEnd;

7. TTI · Time To Interactive

"主线程连续空闲 5 秒,可稳定响应交互"

  • 传统但难精确测量(需要看 long task、FCP、资源加载多重信号)
  • 浏览器不直接暴露 ------ 需要算法推断
  • 建议用 web-vitals 库或 Lighthouse 测,不要手写

8. INP · Interaction to Next Paint(Core Web Vital,2024 替换 FID)

"用户每次交互(点击/输入)到下一次画面更新的耗时"

  • 测 可交互性(FCP/LCP 测"能看",INP 测"能用")
  • 贯穿整个页面生命周期,不是首屏指标
  • 反映 JS 主线程是否卡

测量方式 :强烈建议用 web-vitals 库,手写很复杂

达标线:< 200ms 好 / 200~500ms 可接受 / > 500ms 差


9. CLS · Cumulative Layout Shift(Core Web Vital)

"页面上所有意外的布局偏移累积分数"

  • 图片没写 width/height、字体替换、广告插入都会引发 CLS
  • 不是时间指标,是一个 相对分数
  • 反映视觉稳定性

达标线:< 0.1 好 / 0.1~0.25 可接受 / > 0.25 差


10. TBT · Total Blocking Time

"FCP 到 TTI 之间,主线程被长任务阻塞的总时长"

  • 长任务 = 单次执行 > 50ms 的 JS 任务
  • 反映加载阶段的 JS 臃肿程度
  • Lighthouse 核心指标,但不是 Core Web Vital

三、如何测 · 四种通用方案

方案 适用 优点 缺点
Chrome DevTools Performance 面板 一次性调试 零代码、直观、火焰图详细 手动录制,没法长期监控
Lighthouse 一次性评分 综合报告,含建议 实验室环境,不代表真实用户
自己 PerformanceObserver 长期埋点 灵活、零依赖 要写代码,边界 case 要自己处理
web-vitals 库(Google 官方) 线上监控 规范、跨浏览器、支持 INP/CLS +3KB(但值)

推荐的最小 web-vitals 接入

js 复制代码
import { onCLS, onFCP, onLCP, onINP, onTTFB } from 'web-vitals';

const send = (metric) => {
  // 上报到你的监控后端
  navigator.sendBeacon('/api/metrics', JSON.stringify(metric));
};

onCLS(send);
onFCP(send);
onLCP(send);
onINP(send);
onTTFB(send);

三行代码覆盖所有 Core Web Vitals,Google 官方维护,永远比自写的准。


四、自定义测量:performance.mark / performance.measure

浏览器自动提供的指标只是"公共节点"。你自己关心的节点要自己打标。

js 复制代码
// 标一个时间点
performance.mark('tab-switched');

// 标一段耗时
performance.mark('data-fetch-start');
await fetchData();
performance.mark('data-fetch-end');
performance.measure('data-fetch-duration', 'data-fetch-start', 'data-fetch-end');

// 读出来
const m = performance.getEntriesByName('data-fetch-duration')[0];
console.log(m.duration);

SPA 里最常见的自定义节点:

  • app-script-start:JS 开始执行
  • app-mounted:框架首屏挂载完
  • route-change-start / route-change-end:路由跳转
  • api-call-start / api-call-end:接口调用

五、指标挑选原则(SPA 视角)

你想知道 看这个
服务端/网络慢不慢 TTFB
用户白屏多久 FCP
用户真觉得"能看了"多久 LCP
首屏真正可交互多久 自定义 app-mounted mark
每次点击是否卡顿 INP
页面是否在跳动 CLS
路由跳转多久 自定义 route-change measure
接口慢不慢 Resource Timing API (getEntriesByType('resource'))

六、一句话记住每个指标的"灵魂"

  • TTFB:网络+后端的成绩单
  • FCP:白屏结束的那一刻
  • LCP :用户觉得"页面好了"的那一刻(Google 认可的"加载")
  • DCL:HTML 骨架完成的那一刻
  • Load:HTML 声明的资源全下完(SPA 里不重要)
  • TTI:主线程稳定空闲(理论可交互)
  • INP :每次交互的响应速度(Google 认可的"交互")
  • CLS :页面跳不跳(Google 认可的"稳定")
  • TBT:加载阶段 JS 卡不卡

Core Web Vitals 三件套 = LCP + INP + CLS。这三个是 Google 搜索排名会用的,也是线上监控的最小必要集。其他都是辅助。


七、一条黄金路径建议

不上线:用 Chrome DevTools Performance + Lighthouse 足够,不用写埋点。

上线后 :接 web-vitals + 自建或对接 APM(Sentry / 阿里 ARMS / 自建后端)。监控 Core Web Vitals + 若干自定义 mark 就够。

不要做的事:

  • 手写 TTI / CLS / INP 计算(必错)
  • 在 dev 模式看性能下结论(几乎永远比 prod 慢 2~5 倍)
  • 只看平均值(看 p75 或 p95 才贴近真实用户体验)

相关推荐
deli00737 分钟前
32K 上下文塞满后,AI 最先忘掉什么?120 轮对话实测
前端
deli0072 小时前
手机拍灯为什么有一条条黑纹?PWM 240Hz 实测
前端
wangruofeng6 小时前
AI Models 1.1.0 发布,查大模型价格、对比模型和找 API 地址
前端·aigc·ai编程
wangruofeng6 小时前
给前端开发者的 100 个设计参考网站
前端·设计
星栈10 小时前
视频即代码,Remotion 能做什么、不能做什么
前端·音视频开发
广州华水科技10 小时前
单北斗GNSS位移监测系统的应用与技术解析
前端
用户479492835691510 小时前
从一句话或代码仓到可交互 HTML:开源 Agent 画图技能 Archify v3.2 实测与选型边界
前端·后端·面试
风骏时光牛马12 小时前
生成一个AI多模态标题,仅输出一条标题,无额外文字、问句、备选、配图、文案等任何附加内容,不需要其他的任务服务 只要标题。
前端
wangruofeng13 小时前
从 GIF 到 AVIF:网页图片格式演进与 2026 年选型指南
前端·架构
清晨Coding14 小时前
为什么用 React Developer Tools 查看组件树这么乱?
前端·react.js