前端性能指标详解与优化实战
性能优化做了不少,但以前只知道”要快”,不理解具体指标。系统学习后分享。
核心指标 (Core Web Vitals)
Google 定义了三个核心指标:
| 指标 | 全称 | 说明 | 好的标准 |
|---|---|---|---|
| LCP | Largest Contentful Paint | 最大内容渲染时间 | < 2.5s |
| FID | First Input Delay | 首次输入延迟 | < 100ms |
| CLS | Cumulative Layout Shift | 累积布局偏移 | < 0.1 |
2024 年新增 INP 替代 FID:
| 指标 | 说明 | 好的标准 |
|---|---|---|
| INP | Interaction to Next Paint | 交互到下次绘制 |
指标详解
LCP (最大内容渲染时间)
页面主要内容加载完成的时间。通常是:
- 图片
- 视频封面
- 文字块
测量:
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP:', lastEntry.startTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });
INP (交互到下次绘制)
用户交互后到界面更新的时间。
测量:
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.interactionId) {
console.log('INP:', entry.duration);
}
}
}).observe({ type: 'event', buffered: true });
CLS (累积布局偏移)
页面元素位置变化导致的视觉偏移。
测量:
let clsValue = 0;
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value;
}
}
console.log('CLS:', clsValue);
}).observe({ type: 'layout-shift', buffered: true });
其他重要指标
| 指标 | 说明 | 好的标准 |
|---|---|---|
| TTFB | 首字节时间 | < 800ms |
| FCP | 首次内容绘制 | < 1.8s |
| TTI | 可交互时间 | < 3.8s |
| TBT | 总阻塞时间 | < 200ms |
优化策略
LCP 优化
| 问题 | 解决方案 |
|---|---|
| 服务端响应慢 | CDN、缓存、优化后端 |
| 资源加载慢 | 预加载、压缩、HTTP/2 |
| 渲染阻塞 | 异步加载 JS、内联关键 CSS |
<!-- 预加载关键资源 -->
<link rel="preload" href="hero-image.jpg" as="image">
<!-- 预连接第三方域名 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
INP 优化
| 问题 | 解决方案 |
|---|---|
| 长任务阻塞 | 拆分任务、Web Worker |
| 事件处理慢 | 防抖节流、优化逻辑 |
| 重渲染过多 | React memo、虚拟列表 |
// 拆分长任务
function processLargeArray(array) {
const chunk = 100;
let index = 0;
function processChunk() {
const end = Math.min(index + chunk, array.length);
while (index < end) {
// 处理 array[index]
index++;
}
if (index < array.length) {
requestIdleCallback(processChunk);
}
}
processChunk();
}
CLS 优化
| 问题 | 解决方案 |
|---|---|
| 图片无尺寸 | 设置 width/height |
| 动态内容插入 | 预留空间 |
| 字体加载闪烁 | font-display: swap |
<!-- 设置图片尺寸 -->
<img src="hero.jpg" width="800" height="600" alt="">
<!-- 预留广告位空间 -->
<div class="ad-slot" style="min-height: 250px;">
<!-- 广告加载后填充 -->
</div>
/* 字体加载策略 */
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
font-display: swap;
}
监控方案
Web Vitals 库
npm install web-vitals
import { onLCP, onINP, onCLS } from 'web-vitals';
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
上报数据
function sendToAnalytics(metric) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
page: window.location.pathname,
});
navigator.sendBeacon('/analytics', body);
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
建立基线
| 指标 | P50 | P75 | P95 |
|---|---|---|---|
| LCP | 1.5s | 2.2s | 3.5s |
| INP | 80ms | 120ms | 250ms |
| CLS | 0.02 | 0.08 | 0.15 |
用分位数看分布,不只是平均值。
工具推荐
| 工具 | 用途 |
|---|---|
| Lighthouse | 本地测试、综合评分 |
| PageSpeed Insights | 线上测试、优化建议 |
| Chrome DevTools | 性能分析、火焰图 |
| WebPageTest | 多地点、多设备测试 |
| Sentry Performance | 真实用户监控 |
优化案例
案例:LCP 从 4s 到 1.8s
问题分析:
- 首页大图 2MB,加载慢
- 第三方字体阻塞渲染
- 关键 CSS 在外部文件
优化措施:
| 措施 | 效果 |
|---|---|
| 图片转 WebP + 压缩 | -1.5s |
| 字体预加载 | -0.4s |
| 关键 CSS 内联 | -0.3s |
最终 LCP:1.8s
案例:INP 从 300ms 到 80ms
问题分析:
- 列表滚动事件处理复杂
- 大量 DOM 操作
优化措施:
// 使用 passive 监听器
element.addEventListener('scroll', handler, { passive: true });
// 使用 requestAnimationFrame
let ticking = false;
element.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
handler();
ticking = false;
});
ticking = true;
}
});
总结
性能优化是持续过程,关键是:
- 建立监控:知道现状
- 设定目标:知道要改善多少
- 逐个击破:先解决最大的瓶颈
- 持续跟进:防止退化
不要盲目优化,用数据说话。