性能指标
在高级前端面试中,不仅要知道如何优化,还要知道如何科学地度量性能。Google 提出的 Core Web Vitals(核心 Web 指标) 是目前业界公认的标准。
1. 核心 Web 指标 (Core Web Vitals)
这是 Google 在 2020 年提出的衡量 Web 用户体验的三个核心指标,也是 Lighthouse 评分的重点:
LCP (Largest Contentful Paint) - 最大内容绘制
- 定义:视口内可见的最大图像或文本块的渲染时间。代表了页面的加载性能。
- 标准:
< 2.5s为优秀,> 4.0s为较差。 - 优化方向:提升服务器响应时间、使用 CDN、优化图片/视频体积、预加载关键资源。
FID (First Input Delay) - 首次输入延迟
- 定义:用户首次与页面交互(点击按钮、链接等)到浏览器实际能够开始处理该交互的时间。代表页面的交互性。
- 标准:
< 100ms为优秀,> 300ms为较差。 - 优化方向:减少主线程执行时间(拆分长任务 Long Tasks),使用 Web Worker,减少第三方脚本影响。
- 注:Google 计划在 2024 年用 INP (Interaction to Next Paint) 取代 FID,INP 衡量的是整个页面生命周期内的所有交互延迟。
CLS (Cumulative Layout Shift) - 累积布局偏移
- 定义:页面在整个生命周期内发生的所有意外布局偏移分数的总和。代表页面的视觉稳定性。
- 标准:
< 0.1为优秀,> 0.25为较差。 - 优化方向:为图片和视频指定宽高(或使用
aspect-ratio),不要在现有内容上方动态插入内容(如广告),使用骨架屏(Skeleton)。
2. 其他重要渲染指标
- FP (First Paint) - 首次绘制
- 浏览器首次将像素渲染到屏幕上的时间。此时可能只画了一个背景色。
- FCP (First Contentful Paint) - 首次内容绘制
- 浏览器首次渲染 DOM 内容(文本、图像、SVG 等)的时间。白屏结束的标志。
- TTI (Time to Interactive) - 可交互时间
- 页面从开始加载,到主要子资源加载完毕,且主线程空闲(能够快速响应用户输入)的时间。
- TTFB (Time to First Byte) - 首字节到达时间
- 浏览器接收到服务器返回的第一个字节数据所需的时间。反映了后端服务器处理和网络传输的耗时。
3. 面试高频题:如何获取这些性能指标?
方式 1:Performance API
通过浏览器提供的 window.performance API 获取时间戳进行计算。
// 获取 FP 和 FCP
const paintMetrics = performance.getEntriesByType('paint');
paintMetrics.forEach(metric => {
console.log(`${metric.name}: ${metric.startTime}ms`);
});
// 获取 TTFB
const navigationTiming = performance.getEntriesByType('navigation')[0];
console.log(`TTFB: ${navigationTiming.responseStart - navigationTiming.requestStart}ms`);
方式 2:PerformanceObserver API (现代方案)
由于很多指标(如 LCP、CLS)是动态变化的,使用 PerformanceObserver 可以在指标发生时异步监听到。
// 监听 LCP
const observer = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP:', lastEntry.startTime);
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
方式 3:现成的库
可以直接使用 Google 官方提供的 web-vitals 库,一键获取所有核心指标并上报。
import { onLCP, onFID, onCLS } from 'web-vitals';
onCLS(console.log);
onFID(console.log);
onLCP(console.log);