前端性能指标速查手册

前端性能指标速查手册

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

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 APIgetEntriesByType('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 才贴近真实用户体验)

相关推荐
Developer_Niuge2 小时前
告别翻不动的 1000+ 书签:开源 Chrome / Edge 浏览器书签管理插件 Smart Bookmark 0.2 发布
前端·后端
淹死在鱼塘的程序猿2 小时前
🚀 告别"一次性聊天":揭秘让 AI 智能体越用越聪明的秘密武器 —— Skills
前端·人工智能·agent
掘金安东尼2 小时前
OpenMUSE 全面详解:非扩散Transformer文生图开源基座(对标GPT Image 2)
前端·javascript·面试
~ rainbow~2 小时前
前端转型全栈(六)——深入浅出:文件上传的原理与进阶
前端·http·文件上传
我就是马云飞2 小时前
我废了!大厂10年的我面了20家公司,面试官让我回去等通知!
android·前端·程序员
yizhiyang3 小时前
ECharts实战:滑动缩放+选中背景高亮,打造高颜值统计图表
前端
猫山月3 小时前
Flutter路由演进路线(2026)
前端·flutter
We་ct3 小时前
LeetCode 322. 零钱兑换:动态规划入门实战
前端·算法·leetcode·typescript·动态规划
袋鱼不重3 小时前
Hermes Agent 直连飞书机器人
前端·后端·ai编程