Skip to content

理解浏览器流水线火焰图 ​

本节目标:理解“理解浏览器流水线火焰图”的核心思路,并能把它用于实际开发或面试表达。 下面按

 **“

先学会读图 → 理解浏览器流水线 → 找瓶颈 → 给 Vue 项目下手的切入点

”**

的顺序来讲。截图来自 Chrome DevTools Performance 面板的

 **Main Thread

火焰图**,其中紫色条块是 JavaScript 执行(脚本),绿色是 Rendering 阶段(Style / Layout / Paint),橙色是 Composite / Rasterize 等 GPU‑side。

---
## 1 ·

怎样快速读火焰图| 区域 | 含义 | 关键操作

                                                    |
| -------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------- |
| **Tasks

列(最顶部浅灰/浅黄)

**  |

浏览器把一段连续执行的工作封装成 Task;单个 Task 超过 50 ms 会染成黄。 | Task \< 16 ms 才能保证 60 fps;黄块 = 第一眼就该怀疑的热点。

 |
| **JS Stack

(紫色块,最宽部分)

** |

调用栈:越往上层,越晚进入;持续时间 = 横向长度。 | 把鼠标悬停:提示本函数耗时。找最长的紫色横条 = 重 JS。

      |
| **

渲染步骤(绿色)

**             | Style

、Layout、Paint(有时称 Recalculate Style / Update Layer Tree / Paint)。 | 绿色块长说明样式计算或布局/绘制重。

                         |
| **Composite / GPU

(橙)

**        |

把已绘制的图层合成最终位图。 | 碎片巨多或单块特别长时,考虑 GPU 加速开关 & 图层过多。

      |
**

定位热点**:

1.

先看顶部 Task 是否变黄。

2. Task

内往下看紫色最长块 → 是 JS 逻辑耗时。

3.

若绿色长 → 布局 / 绘制 频繁。

4.

最后看 Bottom‑Up / Call Tree 面板统计百分比。

---
## 2 ·

浏览器一次「绘制循环」顺序 典型瀑布(右侧靠下的 Render + GPU): ``` 用户输入 / 定时器

↓
JavaScript

运行(Task)

↓
Recalculate Style         //

重新计算样式

↓
Layout (Reflow)           //

计算元素几何

↓
Paint (

栅格化位图) // CPU 生成位图

↓
Composite Layers          // GPU

合成

↓
Frame

输出 (16.6 ms 之内) // 成功

 60fps
 截图中可以看到紫色函数栈后面紧跟

patchElement → patch → processElement


(`Vue` 的 `VDOM patch`),然后出现

Recalculate Style / Layout


,和上面顺序一致。

3 · ​


**你这张图的解读**
flushJobs               ← Vue Scheduler

调度批量更新 ReactiveEffect.run ← 触发响应式副作用

    updateComponent
      componentUpdateFn
        patch           ←

虚拟

 DOM diff / patch
          processComponent
          processElement
  • **

**耗时** `1.56 ms**`(提示框里)。

这一行就是

**“


**更新视图的** `JS` **逻辑**`”**`;如果有更多 `state` 改动,会看到 `flushJobs` 拉很长。
  • JS

结束后,下方会出现

Recalculate Style → Layout → Paint → Composite


,但因为时间短,图里没截到绿色块或绿色很窄。

4 · ​


**优化切入点**

> **


**先原则**`**`:只优化瓶颈;别为 `1 ms` 的操作花 `1` 天。
`|` 现象                       `|` 优化思路
                                                                                                                                        |

| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | **


**紫色长条(脚本)**

** | -


拆分大型循环 `/` 递归

→ requestIdleCallback / setTimeout 0<br>-


用

v-show


代替频繁销毁`/`渲染的

v-if<br>-


虚拟滚动(列表多时只渲染可视区)
|

| **Recalculate Style


**频繁**

** | -


降低动态修改 `class/style` 的频率;合并操作`<br>-` 避免 `JS` 读取后立即写入 `style`(触发两次回流)
                                                   |

| **Layout


**长或多**

** | - 避免逐条修改 DOM 大小,批量或用 flex/grid 自动排版\<br\>- 固定容器尺寸,减少 percentage / auto layout | | **Paint/Composite


**重**

** | -


减少

box-shadow, border-radius,


大图透明等耗 `GPU` 绘制`<br>-` 把频繁动画的元素提成独立层:

will-change: transform | | Vue specific | -


设置

:key & v-once


合理复用节点`<br>-` 关闭 `devtools / production build` 看真实耗时

<br>- computed


缓存拆分:避免一级 `computed` 依赖大量响应式源

| **


**建议的检查顺序**`**`:
  1. **

**录一个** `5 s Trace**`,找所有黄色 `Task`,按耗时排序(`Bottom`‑`Up`)。

对 `JS`:按热点函数写 `unit benchmark →` 折半排查(`binary search`)找数据规模触发点。

对 `Layout`:选中绿色块,看 `“Layout invalidated by” →` 哪个元素改动。

持续把长块压到 `< 8 ms`;剩余零星 `1–2 ms` 块通常无需动。

5 · ​


**实战小贴士**
  • **

**保持** `FPS` **图绿色**`**`:`Timeline` 最顶一行里有 `FPS` 折线;红尖刺 `=` 卡顿。
  • **

**性能预算线**`**`:在 `Performance Settings` 开 `“Screenshots” + “Framerate”` 可以直观看。
  • **

**源映射**`**`:生产环境 `profile` 前确保

source-map


打开,否侧函数名全是

`(


匿名`` )` ``。
  • ** 对比快照**:把每一次优化前后录屏比对,确认真有收益,避免幻觉优化。

​


**结论**
  1. **

**先看** `Task` **是否黄**`**`:`> 50 ms` 就是第一目标。
  1. **

**紫** `or` **绿谁更长**

** → JS


还是渲染瓶颈。
  1. **Vue

**工程**`**`:多关注

flushJobs / patch 这一段,如果它经常 \> 5 ms,先从减少响应式依赖、拆分组件、虚拟滚动下手。 4.


每次改动都

**


**录一次** `Profile**`,看火焰图是否真的缩短 `——` 量化迭代才是真优化。
如果你有具体组件或函数想深入分析,贴出代码或更长的火焰图,再继续拆解!

本站总访问 — 次