# Web Vitals 与前端性能治理
30秒提纲:用 PerformanceObserver 采集 LCP/CLS/INP/TTI,找出“最大内容元素、布局位移、交互延迟”的瓶颈;优化遵循“关键路径最小化 + 资源矩阵(图片/字体)+ 代码切割 + 渲染占位 + 缓存与预取”,上线后用阈值告警与对照实验验证。
# 1. 核心指标与阈值(良好/需改进/较差)
- LCP(最大内容绘制):≤2.5s / 2.5–4s / >4s
- CLS(累计布局偏移):≤0.1 / 0.1–0.25 / >0.25
- INP(交互反应):≤200ms / 200–500ms / >500ms(取代 FID)
- TTI(可交互):越小越好(辅助参考)
# 2. 采集与上报
// LCP
new PerformanceObserver((po)=>{
po.getEntries().forEach(e=>{ report('LCP', e.startTime) })
}).observe({ type:'largest-contentful-paint', buffered:true })
// CLS
let cls = 0
new PerformanceObserver((po)=>{
po.getEntries().forEach(e=>{ if(!e.hadRecentInput) cls += e.value })
report('CLS', cls)
}).observe({ type:'layout-shift', buffered:true })
// INP
new PerformanceObserver((po)=>{
po.getEntries().forEach(e=>{ report('INP', e.interactionId ? e.duration : e.processingEnd - e.startTime) })
}).observe({ type:'event', buffered:true, durationThreshold: 16 })
- 上报策略:首包后空闲上报;采样率控制;携带版本/页面/设备标签
# 3. 优化策略矩阵
- 关键路径:移除/延后非关键脚本,分离同步阻塞;HTTP/2 多路复用
- 代码:路由/组件懒加载、动态 import 命名分块、Tree-shaking、SSR/SSG
- 图片:WebP/AVIF、自适应尺寸、Lazy/Decode async、占位图(LQIP)
- 字体:子集化、可变字体、font-display: swap、预加载
- 渲染:骨架屏、优先渲染最大内容元素、减少重排(稳定尺寸/避免 FOIT)
- 缓存:强/协商缓存、Service Worker 预缓存、Prefetch/Preconnect
# 4. 验证与回归
- 实验:前后对比/灰度 A/B;采样≥1% 用户
- 阈值告警:LCP>2.5s、CLS>0.1、INP>200ms 触发
- SourceMap 关联堆栈与版本,快速定位变更影响
# 5. 实战 Checklist(落地即用)
- [ ] 首页最大内容元素图片改 WebP + 固定尺寸 + Preload
- [ ] 路由级代码分割;非首屏组件 defineAsyncComponent
- [ ] 字体子集化(subset)并 preload;font-display: swap
- [ ] 图片懒加载 + decoding="async"
- [ ] 开启 SW 预缓存关键资源
- [ ] 监控平台新增 LCP/CLS/INP 趋势看板