常见前端性能指标
前端性能指标是衡量网站用户体验的重要标准,直接影响用户满意度、SEO 排名和业务转化率。本文将详细介绍各种前端性能指标,帮助开发者理解和优化网站性能。
一、Core Web Vitals 核心指标
Google 在 2020 年推出的 Core Web Vitals 是衡量网站用户体验的三个核心指标,也是 SEO 排名的重要因素。
1. LCP (Largest Contentful Paint) 最大内容绘制
LCP
是指网页在加载过程中,视口(viewport)内最大内容元素渲染完成的时间点。
- “最大内容元素”通常是:
- 图片(
<img>
、background-image
) - 视频的海报帧
- 块级文本元素(
<p>
、<h1>
等)
- 图片(
- 浏览器会:
- 追踪视口中最大的内容元素。
- 记录它完全渲染的时间(例如,图片加载完成或文本绘制完成)。
- 如果稍后出现一个更大的元素(例如,滚动后加载了一张新图片),
LCP
会被更新。
也就是说,LCP 衡量用户在视觉上感觉页面“主要内容”加载完成的速度。
LCP
的性能标准
- 优秀(Good): ≤ 2.5 秒
- 需要改进(Needs Improvement):2.5 - 4 秒
- 差(Poor): > 4 秒
如何测量 LCP
- LCP 可以通过
Performance API
的LargestContentfulPaint
条目捕获。浏览器会持续追踪视口中最大的内容元素,并记录其渲染时间。
// 创建一个 PerformanceObserver 实例来监听性能事件
const observer = new PerformanceObserver((entryList) => {
// getEntries() 返回一个性能条目数组
const entries = entryList.getEntries();
for (const entry of entries) {
// entry.startTime 是 LCP 时间
console.log(`最大内容绘制 (LCP): ${entry.startTime.toFixed(2)}ms`);
// entry.element 是触发 LCP 的 DOM 元素
console.log('LCP 元素:', entry.element);
}
});
// 开始监听 'largest-contentful-paint' 类型的事件
// buffered: true 确保在观察者创建之前发生的事件也能被捕获
observer.observe({ type: 'largest-contentful-paint', buffered: true });
- 也可以在 Chrome DevTools 的
Performance
面板中查看 LCP。打开 DevTools (F12),转到 "Performance" 标签页,录制页面加载过程,LCP 会在时间线上被明确标记出来。
LCP
的常见影响因素
慢的服务器响应:服务器延迟高 → HTML 获取慢 → 资源加载延迟。
渲染阻塞资源:例如大体积的 CSS、JS 阻塞页面渲染。
图片和视频加载慢:首屏大图过大,未使用懒加载/压缩。
前端渲染策略问题:CSR(客户端渲染)比 SSR(服务端渲染)更慢,可能影响首屏 LCP。
优化 LCP
的方法
- 服务器层面优化:使用 CDN、缓存,降低 TTFB(首字节时间)。
- 优化资源加载
- 图片:压缩、WebP/AVIF 格式、懒加载、预加载首屏大图。
- CSS/JS:减少阻塞,使用代码分割。
- 优先渲染关键内容:SSR / SSG(Next.js、Nuxt.js),加快首屏直出。
- 预加载关键资源:
<link rel="preload">
用于提前加载首屏大图或字体。
2. FID (First Input Delay) 首次输入延迟
定义:用户首次与页面交互(点击、触摸、按键)到浏览器实际开始处理事件处理程序的时间。
评判标准:
- 良好:≤ 100 毫秒
- 需要改进:100 - 300 毫秒
- 差:> 300 毫秒
影响 FID 的因素:
- 主线程阻塞
- JavaScript 执行时间过长
- 大型第三方脚本
优化策略:
// 代码分割,按需加载
import { heavyFunction } from './heavy-module.js';
// 使用 Web Workers 处理复杂计算
const worker = new Worker('calculation-worker.js');
worker.postMessage(data);
// 延迟非关键 JavaScript
<script defer src="non-critical.js"></script>;
3. CLS (Cumulative Layout Shift) 累积布局偏移
CLS 衡量的是网页在加载过程中,元素位置发生意外变化的稳定性。
换句话说,它关注的是:
👉 页面在用户交互前,内容是否会乱跳?
比如:
- 你在阅读文章时,突然广告加载进来,把文字往下挤。
- 你准备点按钮,结果按钮被图片挤开了,你点到了别的东西。
这些情况都会增加 CLS 值。
CLS
的计算方式
CLS
是所有单个布局偏移分数的总和,每个分数按以下方式计算:
偏移分数 = 影响因子 (Impact Fraction) × 距离因子 (Distance Fraction)
- 影响因子:受偏移影响的视口区域比例。例如,一个元素从顶部移动到底部,可能会影响 50% 的视口。
- 距离因子:元素移动的距离相对于视口高度(或宽度)的比例。例如,移动了视口高度的 10%,则距离因子为 0.1。
如何测量 CLS
CLS 是通过
LayoutShift
性能条目计算的。浏览器会追踪所有非用户交互触发的布局变化,并计算一个“偏移分数”。jslet clsScore = 0; // 创建 PerformanceObserver 来监听布局偏移事件 const observer = new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // 忽略由用户输入(如点击、滚动)在 500ms 内触发的布局偏移 if (!entry.hadRecentInput) { // entry.value 是单次布局偏移的分数 clsScore += entry.value; console.log(`单次布局偏移分数: ${entry.value.toFixed(4)}`); } } // 累加所有分数得到最终的 CLS console.log(`累积布局偏移 (CLS): ${clsScore.toFixed(4)}`); }); // 开始监听 'layout-shift' 类型的事件 observer.observe({ type: 'layout-shift', buffered: true });
根据 Google 的标准,CLS 分数低于 0.1 是理想的。你可以使用 Chrome DevTools 的 Performance 面板来可视化 CLS,发生偏移的元素会被高亮显示。
常见导致 CLS
的原因
- 图片、广告、
iframe
没有固定尺寸,高度或宽度后加载才撑开。 - 动态插入的内容没有预留空间。
- 使用了 FOIT/FOUT(字体加载闪动)。
- 按钮、表单被动态元素挤开。
如何优化 CLS
- 为 图片、视频、广告 设置固定宽高或使用 aspect-ratio。
- 为动态内容预留空间(骨架屏、占位符)。
- 避免在 已有内容上方 插入新内容。
- 使用 font-display: swap 避免字体闪动。
- 慎用动画或过渡,避免引起大幅度位移。
二、传统性能指标
1. FP (First Paint) 首次绘制,页面开始呈现内容的时刻
First Paint (FP) 表示浏览器首次把任何像素绘制到屏幕上的时间点。它不一定是有意义的内容(可能只是背景色),但标志着用户看到“页面开始有东西出现”了。
如何测量 FP
FP 是第一个渲染里程碑,通常通过
Performance API
来捕获。它发生在浏览器解析完 DOM 和 CSSOM 并开始绘制像素时。以下是测量方法:js// 监听页面加载完成事件 window.addEventListener('load', () => { // 使用 Performance API 获取所有“paint”类型的性能条目 const performanceEntries = window.performance.getEntriesByType('paint'); // 找到名为 'first-paint' 的条目 const fpEntry = performanceEntries.find((entry) => entry.name === 'first-paint'); if (fpEntry) { // fpEntry.startTime 是从页面导航开始到首次绘制发生的时间(毫秒) console.log(`首次绘制 (FP): ${fpEntry.startTime.toFixed(2)}ms`); } else { console.log('浏览器不支持 FP 或无法获取'); } });
这段代码使用 performance.getEntriesByType('paint')
来获取与绘制相关的性能条目,找到 first-paint
条目并记录其 startTime
(以毫秒为单位)。大多数现代浏览器(Chrome、Edge、Firefox)都支持此 API。
FP
代表什么
FP
标志着渲染的开始,表明浏览器已经开始工作。例如,背景颜色的变化或加载指示器的出现都会触发 FP。它通常发生在:
浏览器解析 HTML
<head>
并加载了 CSS。浏览器开始渲染第一个 DOM 元素(例如
<body>
的背景)。
FP
的局限性
FP
只追踪第一个像素的绘制,而不管内容是否有意义。例如,即使用户想看的文章或图片还未加载,一个背景色的变化也会触发 FP
。这正是 FMP
和 LCP
发挥作用的地方。
2. FCP (First Contentful Paint) 首次内容绘制
FCP
是核心网页性能指标之一,用于测量页面第一次渲染“有内容”的时刻。
它标记了用户从打开页面开始,到首次看到非空白内容(文本、图片、SVG、canvas 等)出现在屏幕上的时间。
- ⚠️ FCP ≠ 白屏结束时间,因为即使只出现一个小 logo 或一行字,也会记录为 FCP。。
FCP
测量范围
- Good(良好): ≤ 1.8s
- Needs Improvement(需要改进): 1.8s ~ 3.0s
- Poor(较差): > 3.0s
FCP
的计算过程(浏览器角度)
用户输入 URL,浏览器开始加载资源。
解析 HTML → 构建 DOM 树。
下载并解析 CSS → 构建 CSSOM 树。
DOM + CSSOM → 生成 Render Tree。
浏览器开始绘制第一个非空白内容(文字 / 图片 / svg / canvas)。
👉 这个时刻就是 FCP。
如何测量 FCP
?
- Lighthouse / PageSpeed Insights
- 打开
Chrome DevTools
→Lighthouse
→ 生成报告 → FCP 会显示在性能指标里。
- 打开
- FCP 可以通过
Performance API
中的paint
条目捕获。浏览器在首次绘制“有意义内容”时会生成 "first-contentful-paint
" 条目。
// 创建 PerformanceObserver 实例监听 paint 事件
const observer = new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (entry.name === 'first-contentful-paint') {
// entry.startTime 就是 FCP 时间
console.log(`首次内容绘制 (FCP): ${entry.startTime.toFixed(2)}ms`);
}
}
});
// 监听 paint 类型的性能事件
observer.observe({ type: 'paint', buffered: true });
如何优化 FCP
?
FCP 的本质是 尽快把首个内容绘制到屏幕,所以优化方向是:
减少关键资源阻塞
- 压缩 HTML / CSS / JS,减少解析时间。
- 避免在
<head>
放阻塞渲染的 JS(可以defer
/async
)。
优化 CSS
- 压缩 CSS 文件。
- 使用关键 CSS(Critical CSS)优先渲染首屏内容。
首屏内容优先
- 懒加载非首屏图片
- 提前加载首屏关键图片(
<link rel="preload">
)。
使用 CDN / 缓存
- 静态资源放在
CDN
,减少网络延迟。 - 利用浏览器缓存,加快二次访问。
- 静态资源放在
3. TTI (Time to Interactive) 可交互时间
TTI
表示用户打开页面后,页面主要内容已经渲染完毕,并且能够快速响应点击、输入、滚动等操作的时间点。
换句话说:
- 页面视觉上可能很快就显示出来了(比如
FP
、FCP
已经完成)。 - 但是如果 JS 还在执行长任务(long task),用户点击按钮没有反应,那么还不能算“可交互”。
- TTI 要等到 CPU 空闲,没有阻塞用户交互的大任务,才会被判定完成。
TTI
计算方法(简化版)
- 页面加载后,浏览器开始绘制内容(FP/FCP)。
- 找到 最后一个长任务(>50ms)结束的时间点。
- 在该点之后,页面要 保持至少 5 秒 CPU 相对空闲(无长任务),且网络请求稳定。
- 这个时间点就是 TTI。
优化 TTI
的方法
- 减少长任务 (
long tasks
)- 拆分大块 JS 逻辑,避免阻塞主线程。
- 使用 requestIdleCallback、setTimeout 拆分执行。
- 代码分割 (Code Splitting)
- 只加载首屏需要的 JS,其他的延迟或按需加载。
- 延迟非关键资源加载
- 使用
defer/async
加载非核心 JS。 - 懒加载图片、视频等资源。
- 使用
Web Worker
- 把计算量大的任务丢到 Worker 线程,避免阻塞主线程。
举个例子:
- 页面 2 秒时首屏显示出来(FCP)。
- 但是 JS 逻辑还在加载和执行,按钮点击没反应。
- 到 6 秒时,JS 执行完毕,主线程空闲,页面变得真正可交互。
- 那么 TTI = 6s。
4. TBT (Total Blocking Time) 总阻塞时间
TBT
= 从 FCP
(First Contentful Paint)到 TTI
(Time to Interactive)之间,所有长任务的阻塞时间之和。
长任务(
Long Task
):浏览器主线程上执行时间超过 50ms 的任务。
阻塞时间:
任务执行总时长 - 50ms。(比如一个 JS 执行了 120ms,那么阻塞时间 = 120 - 50 = 70ms)
为什么重要
TBT
可以反映用户在页面 还没完全可交互 时,点击/输入等操作会被延迟响应的程度。- 与
FID
(首次输入延迟) 相关,但FID
依赖用户真实操作,而TBT
可以在实验室环境(Lighthouse 等工具)下测得,因此是 FID 的实验室替代指标。
优化方向
减少 JavaScript 执行时间
- 代码拆分(Code Splitting)
- 按需加载
- 删除无用依赖
减少主线程长任务
- 使用 Web Worker 处理复杂计算
- 避免阻塞式同步操作
优化第三方脚本
- 异步加载(async / defer)
- 移除不必要的统计 / 广告脚本
优化渲染
- 使用虚拟滚动、懒加载图片等