Chrome DevTools 与性能分析
Performance 面板、火焰图、长任务定位、Lighthouse 实战
一、Performance 面板概览
1.1 核心区域
┌─────────────────────────────────────────────────────────────────────────┐
│ Performance 面板 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ [Record] [Reload] [Screenshot] [CPU 4x] [Network] [Memory] │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ FPS │ CPU │ NET │ 主线程火焰图 (Main) │ │
│ │ │ │ │ ┌─────┬─────┬─────────────┬─────┐ │ │
│ │ │ │ │ │Script│Layout│ Paint │ ... │ │ │
│ │ │ │ │ └─────┴─────┴─────────────┴─────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Summary │ Bottom-Up │ Call Tree │ Event Log │ │
│ │ 选中任务的耗时分布 │ 按耗时排序 │ 调用栈树 │ 事件列表 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘1.2 录制步骤
- 打开 DevTools → Performance
- 勾选 Screenshots(可选,便于分析卡顿时刻)
- 勾选 Network(可选,看网络与主线程关系)
- 点击 Record 或 Reload 开始录制
- 执行目标操作(如滚动、点击)
- 点击 Stop 结束
二、火焰图解读
2.1 主线程火焰图
- 横轴:时间线
- 纵轴:调用栈深度,上层调用下层
- 颜色:
- 黄色:Script(JS 执行)
- 紫色:Rendering(Layout、Paint)
- 绿色:Painting
2.2 识别长任务 (Long Task)
长任务 = 主线程连续执行超过 50ms 的任务
┌────────────────────────────────────────────────────────────┐
│ ████████████████████████████████████████ ← 长任务 (>50ms) │
│ ████ ████ ████ ████ ████ ← 短任务,可被中断 │
└────────────────────────────────────────────────────────────┘- 长任务会阻塞输入响应,导致 FID/INP 变差
- 红色三角标记表示可能影响交互
2.3 常见性能问题
| 现象 | 可能原因 |
|---|---|
| 大片黄色 Script | JS 执行过长,考虑拆分或 Worker |
| 频繁紫色 Layout | 强制同步布局,读写 layout 属性交错 |
| 长任务内有 Recalculate Style | 样式计算耗时,减少选择器复杂度 |
| 大量 Paint | 重绘频繁,考虑合成层优化 |
三、长任务定位与优化
3.1 定位长任务
- 在火焰图中找到宽度 > 50ms 的黄色块
- 点击展开,查看 Bottom-Up 或 Call Tree
- 找到耗时最高的函数
3.2 优化策略
javascript
// ❌ 长任务:一次性处理大量数据
function processAll(items) {
items.forEach(item => heavyWork(item));
}
// ✅ 拆分:使用 requestIdleCallback 或 requestAnimationFrame
function processInChunks(items) {
let i = 0;
function process() {
const deadline = performance.now() + 16; // 约一帧
while (i < items.length && performance.now() < deadline) {
heavyWork(items[i++]);
}
if (i < items.length) requestIdleCallback(process);
}
requestIdleCallback(process);
}3.3 使用 Scheduler.yield(实验性)
javascript
// Chrome 108+ 实验性 API
if ('scheduler' in globalThis && 'yield' in scheduler) {
await scheduler.yield(); // 让出主线程
}四、内存分析
4.1 Memory 面板
- Heap snapshot:堆快照,查看对象分布
- Allocation instrumentation:分配时间线,定位泄漏
- Allocation sampling:采样分配,低开销
4.2 内存泄漏排查
- 打开页面,执行操作
- 拍快照 1
- 执行可能泄漏的操作(如打开/关闭弹窗)
- 手动 GC(点击垃圾桶图标)
- 拍快照 2
- 选择 Comparison,对比快照 1 和 2
- 查看 Detached 的 DOM 节点或未释放的闭包引用
4.3 常见泄漏场景
javascript
// ❌ 泄漏:定时器未清除
const id = setInterval(() => {}, 1000);
// 组件卸载时未 clearInterval(id)
// ❌ 泄漏:事件监听未移除
element.addEventListener('click', handler);
// 组件卸载时未 removeEventListener
// ❌ 泄漏:闭包引用大对象
function createClosure() {
const bigData = new Array(1000000).fill(0);
return () => console.log(bigData.length); // bigData 无法释放
}五、Lighthouse 使用
5.1 运行方式
- DevTools → Lighthouse 面板
- 选择 Performance、Accessibility 等
- 选择 Mobile 或 Desktop
- 点击 Analyze page load
5.2 核心指标
| 指标 | 说明 | 良好值 |
|---|---|---|
| FCP | 首次内容绘制 | < 1.8s |
| LCP | 最大内容绘制 | < 2.5s |
| TBT | 总阻塞时间 | < 200ms |
| CLS | 累积布局偏移 | < 0.1 |
| Speed Index | 内容填充速度 | < 3.4s |
5.3 常见优化建议
- Reduce JavaScript execution time:代码分割、懒加载、减少首屏 JS
- Eliminate render-blocking resources:内联关键 CSS、异步非关键 JS
- Properly size images:使用 srcset、现代格式 (WebP/AVIF)
- Avoid long main-thread tasks:拆分长任务
六、Network 面板与性能
6.1 关键请求
- Waterfall:请求时序,看阻塞关系
- Priority:请求优先级(High/Medium/Low)
- Size:传输大小 vs 实际大小(gzip 后)
6.2 性能相关
- 检查是否有请求阻塞渲染(如同步 script)
- 检查关键资源是否使用 preload
- 检查是否有不必要的重复请求
七、Rendering 工具
7.1 常用 overlay
- Paint flashing:重绘区域闪烁
- Layout Shift Regions:布局偏移区域高亮
- Frame Rendering Stats:FPS 显示
- Scrolling performance issues:滚动性能问题
7.2 使用方式
DevTools → 按 Esc 打开抽屉 → Rendering 标签
八、高频面试题
Q1: 如何排查页面卡顿?
答案:用 Performance 录制,看主线程火焰图,定位长任务(>50ms 的黄色块),用 Bottom-Up 找到耗时函数,拆分任务或使用 Worker。
Q2: 如何排查内存泄漏?
答案:Memory 面板拍两次 Heap snapshot,对比 Detached DOM 或未释放对象;或用 Allocation instrumentation 看分配时间线。
Q3: Lighthouse 的 LCP 和 TBT 分别代表什么?
答案:LCP 是最大内容绘制时间,首屏主要内容加载完成;TBT 是总阻塞时间,主线程被长任务阻塞的总时长。
Q4: 火焰图中黄色、紫色、绿色分别代表什么?
答案:黄色是 Script(JS 执行),紫色是 Rendering(Layout/Paint),绿色是 Painting。