Chrome DevTools 性能分析完全指南
为什么需要性能分析工具
在前端开发中,我们经常会遇到这样的问题:"页面加载慢"、"滚动卡顿"、"动画不流畅"。但仅凭直觉很难定位问题的根源。
Chrome DevTools 的 Performance 面板就是为解决这个问题而生的。它能够:
- 精确测量:记录页面的每一帧、每一次函数调用
- 可视化呈现:通过火焰图直观展示性能瓶颈
- 深度分析:揭示 JavaScript 执行、布局计算、渲染绑定的耗时
- 量化改进:提供可对比的性能指标
性能问题诊断流程:
用户反馈 → 复现问题 → 录制性能 → 分析火焰图 → 定位瓶颈 → 优化代码 → 验证改进
↑ ↓
└──────────────────── 持续监控 ←─────────────────────────────────────┘
Performance 面板核心功能
打开和配置面板
打开 Chrome DevTools(F12 或 Cmd+Option+I),切换到 Performance 标签页。
Performance 面板布局:
┌─────────────────────────────────────────────────────────────┐
│ ● 录制 ⟳ 刷新录制 🗑 清除 ⬇ 导入 ⬆ 导出 ⚙ 设置 │
├─────────────────────────────────────────────────────────────┤
│ 时间轴概览区 (Overview) │
│ ████████░░░░░████████░░░░░░░░░████████░░░░░ │
├─────────────────────────────────────────────────────────────┤
│ 详细时间轴 (Main Thread / Frames / Network...) │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Network ▓▓▓░░░░░░░▓▓▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │ │
│ │ Frames ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ ▮ │ │
│ │ Main ████████████░░░░░████████████░░░░░░░░░░░░░░ │ │
│ │ GPU ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │ │
│ └───────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 详情面板 (Summary / Bottom-Up / Call Tree / Event Log) │
└─────────────────────────────────────────────────────────────┘
关键设置选项:
// 点击齿轮图标可配置以下选项:
const performanceSettings = {
// CPU 节流:模拟低端设备
cpuThrottling: '4x slowdown', // 或 '6x slowdown'
// 网络节流:模拟慢速网络
networkThrottling: 'Slow 3G',
// 禁用 JavaScript 采样:获取完整调用栈
disableJavaScriptSamples: false,
// 启用高级绘制工具
enableAdvancedPaintInstrumentation: true,
// 截图:捕获每帧的页面截图
screenshots: true,
// 内存:显示内存使用情况
memory: true
};
录制性能数据
有两种录制方式:
// 方式1:手动录制(适合交互分析)
// 1. 点击录制按钮
// 2. 执行要分析的操作
// 3. 点击停止
// 方式2:刷新录制(适合加载分析)
// 1. 点击刷新录制按钮
// 2. 页面自动刷新并开始录制
// 3. 页面加载完成后自动停止
// 方式3:通过代码触发录制
async function recordPerformance() {
// 开始录制
await chrome.devtools.inspectedWindow.eval(
'console.profile("MyProfile")'
);
// 执行操作...
await performHeavyOperation();
// 停止录制
await chrome.devtools.inspectedWindow.eval(
'console.profileEnd("MyProfile")'
);
}
火焰图深度解读
理解火焰图结构
火焰图是性能分析的核心工具,理解它的结构至关重要:
火焰图结构说明:
时间轴 →→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→
┌─────────────────────────────────────────────────────────┐
│ Event (click) │ ← 顶层:触发事件
├─────────────────────────────────────────────────────────┤
│ Function Call (handleClick) │ ← 事件处理函数
├───────────────────────────┬─────────────────────────────┤
│ updateData() - 15ms │ renderUI() - 25ms │ ← 子函数调用
├─────────────┬─────────────┼──────────────┬──────────────┤
│ fetch - 10ms│ parse - 5ms │ layout - 10ms│ paint - 15ms │ ← 更深层调用
└─────────────┴─────────────┴──────────────┴──────────────┘
颜色编码:
🟨 黄色 = JavaScript 执行
🟪 紫色 = 布局/回流 (Layout)
🟩 绿色 = 绑制 (Paint)
🟦 蓝色 = 解析 (Parse HTML/CSS)
⬜ 灰色 = 其他/空闲
关键指标:
- 宽度 = 执行时间
- 深度 = 调用层级
- 位置 = 执行顺序
识别性能瓶颈的模式
// 模式1:长任务(Long Task)
// 特征:主线程上超过 50ms 的黄色块
// 影响:阻塞用户交互,导致页面无响应
// 优化前:一个 200ms 的长任务
function processLargeData(data) {
const result = [];
for (let i = 0; i < data.length; i++) {
result.push(heavyCalculation(data[i]));
}
return result;
}
// 优化后:分割成多个小任务
async function processLargeDataOptimized(data) {
const result = [];
const CHUNK_SIZE = 100;
for (let i = 0; i < data.length; i += CHUNK_SIZE) {
const chunk = data.slice(i, i + CHUNK_SIZE);
// 每处理一批,让出主线程
await new Promise(resolve => setTimeout(resolve, 0));
for (const item of chunk) {
result.push(heavyCalculation(item));
}
}
return result;
}
// 模式2:频繁的布局抖动(Layout Thrashing)
// 特征:火焰图中出现多次紫色的 Layout 块
// 影响:强制同步布局,严重影响性能
// 优化前:读写交替导致布局抖动
function updateElements(elements) {
elements.forEach(el => {
const height = el.offsetHeight; // 读取 - 触发布局
el.style.height = height + 10 + 'px'; // 写入 - 使布局失效
});
}
// 优化后:批量读取,批量写入
function updateElementsOptimized(elements) {
// 批量读取
const heights = elements.map(el => el.offsetHeight);
// 批量写入
elements.forEach((el, i) => {
el.style.height = heights[i] + 10 + 'px';
});
}
// 模式3:频繁的垃圾回收(GC)
// 特征:时间轴上频繁出现 Minor GC / Major GC
// 影响:暂停 JavaScript 执行,导致卡顿
// 优化前:频繁创建临时对象
function animate() {
requestAnimationFrame(() => {
// 每帧创建新对象 - 产生垃圾
const position = { x: Math.random() * 100, y: Math.random() * 100 };
updatePosition(position);
animate();
});
}
// 优化后:复用对象
const position = { x: 0, y: 0 }; // 复用对象
function animateOptimized() {
requestAnimationFrame(() => {
// 修改现有对象,避免创建新对象
position.x = Math.random() * 100;
position.y = Math.random() * 100;
updatePosition(position);
animateOptimized();
});
}
分析面板详解
Summary 面板
Summary 面板提供选中时间范围内的活动总览:
Summary 面板内容:
┌────────────────────────────────────────────┐
│ Total Time: 1523.4 ms │
├────────────────────────────────────────────┤
│ Loading: 125.3 ms ████░░░░░░░ 8.2% │ ← 资源加载时间
│ Scripting: 856.7 ms ████████████ 56.2% │ ← JavaScript 执行
│ Rendering: 312.4 ms ██████░░░░░ 20.5% │ ← 布局和绘制
│ Painting: 128.6 ms ███░░░░░░░░ 8.4% │ ← 实际绘制到屏幕
│ System: 67.2 ms █░░░░░░░░░░ 4.4% │ ← 浏览器内部操作
│ Idle: 33.2 ms █░░░░░░░░░░ 2.2% │ ← 空闲时间
└────────────────────────────────────────────┘
各阶段含义:
const activityTypes = {
// Loading - 加载阶段
loading: {
activities: [
'Parse HTML', // 解析 HTML
'Parse Stylesheet', // 解析 CSS
'Finish Loading', // 完成资源加载
'Receive Data' // 接收网络数据
],
optimization: '减少资源体积,使用缓存'
},
// Scripting - 脚本执行
scripting: {
activities: [
'Evaluate Script', // 评估/执行脚本
'Compile Script', // 编译脚本
'Run Microtasks', // 执行微任务
'Event (click, etc.)', // 事件处理
'Timer Fired', // 定时器触发
'XHR Ready State Change' // XHR 状态变化
],
optimization: '代码分割,延迟执行,Web Worker'
},
// Rendering - 渲染计算
rendering: {
activities: [
'Recalculate Style', // 重新计算样式
'Layout', // 布局计算
'Update Layer Tree', // 更新图层树
'Pre-Paint' // 预绑制准备
],
optimization: '减少 DOM 操作,避免强制同步布局'
},
// Painting - 绘制
painting: {
activities: [
'Paint', // 绑制
'Composite Layers', // 合成图层
'Rasterize Paint' // 光栅化
],
optimization: '使用 transform/opacity,减少绑制区域'
}
};
Bottom-Up 和 Call Tree
这两个面板帮助定位具体的性能热点:
Bottom-Up(自底向上):
- 显示消耗时间最多的函数
- 适合找出"哪个函数最慢"
┌─────────────────────────────────────────────────────────┐
│ Self Time Total Time Activity │
├─────────────────────────────────────────────────────────┤
│ 245.3 ms 856.7 ms heavyCalculation │
│ 89.2 ms 312.4 ms updateDOM │
│ 67.8 ms 67.8 ms JSON.parse │
│ 45.6 ms 145.2 ms renderList │
└─────────────────────────────────────────────────────────┘
Call Tree(调用树):
- 显示函数调用的层级关系
- 适合理解"执行流程是什么"
┌─────────────────────────────────────────────────────────┐
│ ▼ main 1523.4 ms │
│ ▼ handleClick 856.7 ms │
│ ▼ processData 456.3 ms │
│ ● heavyCalculation 245.3 ms │
│ ● formatResult 128.4 ms │
│ ▼ updateUI 312.4 ms │
│ ● renderList 145.2 ms │
│ ● updateDOM 89.2 ms │
└─────────────────────────────────────────────────────────┘
实战案例:诊断页面卡顿
案例场景
用户报告:滚动列表页面时出现明显卡顿。
步骤1:录制性能数据
// 录制前的准备
// 1. 清除浏览器缓存
// 2. 关闭其他标签页
// 3. 开启 CPU 4x 节流(模拟低端设备)
// 4. 开始录制 → 滚动页面 → 停止录制
步骤2:分析火焰图
录制结果分析:
时间轴(每帧 16.67ms 目标):
Frame 1: ████████████████████████████████████████████ 52ms ❌
Frame 2: ████████████████████████████████████████████ 48ms ❌
Frame 3: ████████████████████████████████████████████████████ 67ms ❌
Frame 4: ████████████████ 18ms ✓
火焰图详情:
┌──────────────────────────────────────────────────────────┐
│ scroll (Event) │
├──────────────────────────────────────────────────────────┤
│ onScroll │
├──────────────────────────┬───────────────────────────────┤
│ updateVisibleItems │ recalculateLayout │
├──────────────┬───────────┼───────────────────────────────┤
│forEach - 15ms│render-25ms│ Layout (forced) - 35ms │ ← 问题!
└──────────────┴───────────┴───────────────────────────────┘
发现问题:
1. 每次滚动都触发完整的列表渲染
2. 存在强制同步布局(Layout forced)
步骤3:定位问题代码
// 问题代码
class VirtualList {
onScroll(event) {
const items = this.getAllItems();
// 问题1:每次滚动都遍历所有项目
items.forEach(item => {
// 问题2:在循环中读取 DOM 属性
const rect = item.element.getBoundingClientRect();
if (this.isInViewport(rect)) {
// 问题3:立即修改 DOM
item.element.style.display = 'block';
item.element.innerHTML = this.renderItem(item.data);
} else {
item.element.style.display = 'none';
}
});
}
}
步骤4:优化代码
// 优化后的代码
class OptimizedVirtualList {
constructor() {
this.scrollHandler = this.throttle(this.onScroll.bind(this), 16);
this.pendingUpdate = null;
}
// 优化1:节流滚动事件
throttle(fn, delay) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
fn.apply(this, args);
}
};
}
onScroll(event) {
// 优化2:使用 requestAnimationFrame 批量更新
if (this.pendingUpdate) {
cancelAnimationFrame(this.pendingUpdate);
}
this.pendingUpdate = requestAnimationFrame(() => {
this.updateVisibleItems();
});
}
updateVisibleItems() {
const scrollTop = this.container.scrollTop;
const viewportHeight = this.container.clientHeight;
// 优化3:只计算可见范围,不遍历所有项目
const startIndex = Math.floor(scrollTop / this.itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(viewportHeight / this.itemHeight) + 1,
this.items.length
);
// 优化4:使用 DocumentFragment 批量 DOM 操作
const fragment = document.createDocumentFragment();
for (let i = startIndex; i < endIndex; i++) {
const element = this.getOrCreateElement(i);
element.style.transform = `translateY(${i * this.itemHeight}px)`;
fragment.appendChild(element);
}
// 优化5:一次性更新 DOM
this.contentContainer.innerHTML = '';
this.contentContainer.appendChild(fragment);
}
// 优化6:对象池复用 DOM 元素
getOrCreateElement(index) {
if (this.elementPool.length > 0) {
const element = this.elementPool.pop();
this.updateElement(element, this.items[index]);
return element;
}
return this.createElement(this.items[index]);
}
}
步骤5:验证优化效果
优化后录制结果:
时间轴:
Frame 1: ████████ 12ms ✓
Frame 2: ██████████ 14ms ✓
Frame 3: ████████ 11ms ✓
Frame 4: ██████████ 15ms ✓
性能提升:
- 平均帧时间:52ms → 13ms(提升 75%)
- 帧率:19 FPS → 60 FPS
- Layout 时间:35ms → 2ms
高级技巧
使用 Performance API 程序化分析
// 创建性能测量工具类
class PerformanceAnalyzer {
constructor() {
this.marks = new Map();
}
// 标记开始点
start(name) {
performance.mark(`${name}-start`);
this.marks.set(name, performance.now());
}
// 标记结束点并计算耗时
end(name) {
performance.mark(`${name}-end`);
performance.measure(name, `${name}-start`, `${name}-end`);
const startTime = this.marks.get(name);
const duration = performance.now() - startTime;
this.marks.delete(name);
return {
name,
duration,
timestamp: Date.now()
};
}
// 获取所有测量结果
getEntries(name) {
return performance.getEntriesByName(name);
}
// 清理测量数据
clear() {
performance.clearMarks();
performance.clearMeasures();
this.marks.clear();
}
// 分析资源加载性能
analyzeResources() {
const resources = performance.getEntriesByType('resource');
return resources.map(resource => ({
name: resource.name,
type: resource.initiatorType,
duration: resource.duration,
transferSize: resource.transferSize,
// 关键时间点
timing: {
dns: resource.domainLookupEnd - resource.domainLookupStart,
tcp: resource.connectEnd - resource.connectStart,
ttfb: resource.responseStart - resource.requestStart,
download: resource.responseEnd - resource.responseStart
}
}));
}
// 分析长任务
observeLongTasks(callback) {
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
callback({
duration: entry.duration,
startTime: entry.startTime,
attribution: entry.attribution
});
}
});
observer.observe({ entryTypes: ['longtask'] });
return observer;
}
}
// 使用示例
const analyzer = new PerformanceAnalyzer();
// 测量函数执行时间
analyzer.start('dataProcessing');
await processLargeDataset();
const result = analyzer.end('dataProcessing');
console.log(`数据处理耗时: ${result.duration.toFixed(2)}ms`);
// 监控长任务
analyzer.observeLongTasks((task) => {
console.warn(`检测到长任务: ${task.duration.toFixed(2)}ms`);
});
自动化性能测试
// 使用 Puppeteer 进行自动化性能测试
const puppeteer = require('puppeteer');
async function runPerformanceTest(url) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// 启用性能追踪
await page.tracing.start({
path: 'trace.json',
screenshots: true
});
// 模拟移动设备
await page.emulate(puppeteer.devices['iPhone 12']);
// 设置 CPU 节流
const client = await page.target().createCDPSession();
await client.send('Emulation.setCPUThrottlingRate', { rate: 4 });
// 收集性能指标
await page.goto(url, { waitUntil: 'networkidle0' });
const metrics = await page.metrics();
const performanceTiming = await page.evaluate(() => {
const timing = performance.timing;
return {
// 页面加载时间
pageLoad: timing.loadEventEnd - timing.navigationStart,
// DOM 解析时间
domParse: timing.domComplete - timing.domLoading,
// 首字节时间
ttfb: timing.responseStart - timing.requestStart,
// DOM 可交互时间
domInteractive: timing.domInteractive - timing.navigationStart
};
});
// 停止追踪
await page.tracing.stop();
await browser.close();
return {
metrics,
performanceTiming,
traceFile: 'trace.json'
};
}
// 性能基准测试
async function benchmarkPage(url, runs = 5) {
const results = [];
for (let i = 0; i < runs; i++) {
const result = await runPerformanceTest(url);
results.push(result.performanceTiming);
}
// 计算平均值
const average = {
pageLoad: avg(results.map(r => r.pageLoad)),
domParse: avg(results.map(r => r.domParse)),
ttfb: avg(results.map(r => r.ttfb)),
domInteractive: avg(results.map(r => r.domInteractive))
};
return {
runs,
results,
average,
// 性能评级
grade: getPerformanceGrade(average)
};
}
function avg(arr) {
return arr.reduce((a, b) => a + b, 0) / arr.length;
}
function getPerformanceGrade(timing) {
if (timing.pageLoad < 1000) return 'A';
if (timing.pageLoad < 2500) return 'B';
if (timing.pageLoad < 4000) return 'C';
return 'D';
}
性能分析报告生成
// 生成性能分析报告
class PerformanceReporter {
constructor() {
this.data = {
timestamp: new Date().toISOString(),
metrics: {},
issues: [],
recommendations: []
};
}
// 收集页面性能数据
async collectData() {
// Core Web Vitals
this.data.metrics.webVitals = await this.getWebVitals();
// 资源加载分析
this.data.metrics.resources = this.analyzeResources();
// JavaScript 执行分析
this.data.metrics.javascript = await this.analyzeJavaScript();
// 识别问题
this.identifyIssues();
// 生成建议
this.generateRecommendations();
return this.data;
}
async getWebVitals() {
return new Promise((resolve) => {
const vitals = {};
// LCP
new PerformanceObserver((list) => {
const entries = list.getEntries();
vitals.lcp = entries[entries.length - 1].startTime;
}).observe({ entryTypes: ['largest-contentful-paint'] });
// FID
new PerformanceObserver((list) => {
vitals.fid = list.getEntries()[0].processingStart -
list.getEntries()[0].startTime;
}).observe({ entryTypes: ['first-input'] });
// CLS
let clsValue = 0;
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value;
}
}
vitals.cls = clsValue;
}).observe({ entryTypes: ['layout-shift'] });
// 等待收集
setTimeout(() => resolve(vitals), 5000);
});
}
analyzeResources() {
const resources = performance.getEntriesByType('resource');
// 按类型分组
const byType = {};
resources.forEach(r => {
const type = r.initiatorType;
if (!byType[type]) {
byType[type] = { count: 0, totalSize: 0, totalTime: 0 };
}
byType[type].count++;
byType[type].totalSize += r.transferSize || 0;
byType[type].totalTime += r.duration;
});
// 找出最慢的资源
const slowest = [...resources]
.sort((a, b) => b.duration - a.duration)
.slice(0, 5);
return { byType, slowest };
}
identifyIssues() {
const { webVitals, resources } = this.data.metrics;
// LCP 问题
if (webVitals.lcp > 2500) {
this.data.issues.push({
severity: webVitals.lcp > 4000 ? 'critical' : 'warning',
type: 'LCP',
message: `LCP 为 ${webVitals.lcp.toFixed(0)}ms,超过 2.5s 阈值`,
value: webVitals.lcp
});
}
// FID 问题
if (webVitals.fid > 100) {
this.data.issues.push({
severity: webVitals.fid > 300 ? 'critical' : 'warning',
type: 'FID',
message: `FID 为 ${webVitals.fid.toFixed(0)}ms,超过 100ms 阈值`,
value: webVitals.fid
});
}
// 大资源问题
resources.slowest.forEach(r => {
if (r.duration > 1000) {
this.data.issues.push({
severity: 'warning',
type: 'SlowResource',
message: `资源加载过慢: ${r.name.split('/').pop()}`,
value: r.duration
});
}
});
}
generateRecommendations() {
this.data.issues.forEach(issue => {
switch (issue.type) {
case 'LCP':
this.data.recommendations.push(
'优化最大内容绘制(LCP):预加载关键资源、优化服务器响应时间、使用 CDN'
);
break;
case 'FID':
this.data.recommendations.push(
'减少首次输入延迟(FID):分割长任务、延迟非关键 JavaScript、使用 Web Worker'
);
break;
case 'SlowResource':
this.data.recommendations.push(
'优化慢资源:启用压缩、使用缓存、考虑懒加载'
);
break;
}
});
}
// 生成 HTML 报告
toHTML() {
return `
<!DOCTYPE html>
<html>
<head>
<title>性能分析报告</title>
<style>
body { font-family: system-ui; max-width: 800px; margin: 0 auto; padding: 20px; }
.metric { padding: 10px; margin: 10px 0; border-radius: 8px; }
.good { background: #d4edda; }
.warning { background: #fff3cd; }
.critical { background: #f8d7da; }
</style>
</head>
<body>
<h1>性能分析报告</h1>
<p>生成时间: ${this.data.timestamp}</p>
<h2>Core Web Vitals</h2>
${this.renderWebVitals()}
<h2>发现的问题</h2>
${this.renderIssues()}
<h2>优化建议</h2>
<ul>
${this.data.recommendations.map(r => `<li>${r}</li>`).join('')}
</ul>
</body>
</html>
`;
}
renderWebVitals() {
const { webVitals } = this.data.metrics;
return `
<div class="metric ${webVitals.lcp <= 2500 ? 'good' : webVitals.lcp <= 4000 ? 'warning' : 'critical'}">
<strong>LCP:</strong> ${webVitals.lcp?.toFixed(0) || 'N/A'}ms
</div>
<div class="metric ${webVitals.fid <= 100 ? 'good' : webVitals.fid <= 300 ? 'warning' : 'critical'}">
<strong>FID:</strong> ${webVitals.fid?.toFixed(0) || 'N/A'}ms
</div>
<div class="metric ${webVitals.cls <= 0.1 ? 'good' : webVitals.cls <= 0.25 ? 'warning' : 'critical'}">
<strong>CLS:</strong> ${webVitals.cls?.toFixed(3) || 'N/A'}
</div>
`;
}
renderIssues() {
return this.data.issues.map(issue => `
<div class="metric ${issue.severity}">
<strong>${issue.type}:</strong> ${issue.message}
</div>
`).join('');
}
}
常见问题与解答
Q1: 火焰图中出现 "Forced reflow" 是什么意思?
// Forced reflow(强制回流)发生在以下情况:
// 在修改 DOM 后立即读取布局属性
// 触发强制回流的属性读取:
const layoutTriggers = [
'offsetTop', 'offsetLeft', 'offsetWidth', 'offsetHeight',
'scrollTop', 'scrollLeft', 'scrollWidth', 'scrollHeight',
'clientTop', 'clientLeft', 'clientWidth', 'clientHeight',
'getComputedStyle()', 'getBoundingClientRect()'
];
// 错误示例
element.style.width = '100px';
console.log(element.offsetWidth); // 触发强制回流!
// 正确做法
const width = element.offsetWidth; // 先读取
element.style.width = '100px'; // 后写入
Q2: 如何区分 "self time" 和 "total time"?
Self Time vs Total Time:
函数 A(total: 100ms)
├── 自身代码执行:30ms ← Self Time
└── 调用函数 B:70ms
└── 函数 B(total: 70ms)
├── 自身代码:50ms ← B 的 Self Time
└── 调用函数 C:20ms
└── 函数 C(total: 20ms, self: 20ms)
分析时:
- 关注 Self Time 高的函数 = 找到性能热点
- 关注 Total Time 高的调用链 = 理解性能消耗的来源
Q3: 如何判断是 CPU 瓶颈还是 I/O 瓶颈?
CPU 瓶颈特征:
- 火焰图中黄色(JavaScript)块占比高
- 主线程几乎没有空闲时间
- FPS 持续低于 60
I/O 瓶颈特征:
- 火焰图中有大量等待时间(灰色间隙)
- Network 面板显示资源加载慢
- 主线程有空闲但页面仍然卡顿
解决方案:
CPU 瓶颈 → 优化代码、使用 Web Worker、延迟非关键脚本
I/O 瓶颈 → 预加载、缓存、CDN、资源压缩
最佳实践总结
性能分析最佳实践清单:
录制准备:
✓ 使用隐身模式排除插件干扰
✓ 关闭其他标签页
✓ 开启 CPU/网络节流模拟真实环境
✓ 录制多次取平均值
分析技巧:
✓ 先看 Summary 了解时间分布
✓ 用 Bottom-Up 找性能热点函数
✓ 用 Call Tree 理解调用链
✓ 关注长任务(>50ms)和强制回流
常见优化方向:
✓ JavaScript:分割长任务、延迟执行、Web Worker
✓ Layout:批量 DOM 操作、避免布局抖动
✓ Paint:使用 transform 代替 top/left
✓ 资源:预加载、缓存、压缩、CDN
通过系统地使用 Chrome DevTools Performance 面板,你可以从"感觉页面慢"升级到"精确知道哪里慢、为什么慢、如何优化"。这是每个前端开发者的必备技能。


