Vue 的虚拟 DOM Diff 算法是怎样的?

Vue Diff 策略

Vue 的 Diff 算法基于同层比较,使用双端比较(Vue2)和最长递增子序列(Vue3)优化。

Vue2 双端比较

使用 4 个指针:旧头、旧尾、新头、新尾

旧:[A, B, C, D]
     ↑head    ↑tail
新:[D, A, B, C]
     ↑head    ↑tail

比较过程:
1. 旧头 vs 新头 → A vs D ✗
2. 旧尾 vs 新尾 → D vs C ✗
3. 旧头 vs 新尾 → A vs C ✗
4. 旧尾 vs 新头 → D vs D ✓ → 移动 D 到前面
重复直到完成

Vue3 快速 Diff + 最长递增子序列

Vue3 改进了 Diff 算法:

  1. 从头同步:从头部开始,遇到不同的就停止
  2. 从尾同步:从尾部开始,遇到不同的就停止
  3. 处理中间部分:
    • 如果新节点多 → 挂载新节点
    • 如果旧节点多 → 卸载旧节点
    • 如果都有 → 使用最长递增子序列最小化 DOM 移动
旧:[A, B, C, D, E]
新:[A, D, C, B, E]

头部同步:A ✓
尾部同步:E ✓
中间:旧 [B, C, D] → 新 [D, C, B]

新中间在旧中间的位置:[3, 2, 1](D=3, C=2, B=1)
最长递增子序列:[2, 1](C, B 不需要移动)
只需移动 D

Key 的作用

// 有 key:精确匹配,最小化 DOM 操作
// 旧:[{key:1, v:A}, {key:2, v:B}]
// 新:[{key:2, v:B}, {key:1, v:A}]
// 结果:移动节点,不销毁重建

// 无 key:按位置比较,内容不同就更新
// 旧:[A, B]
// 新:[B, A]
// 结果:A→B(更新DOM),B→A(更新DOM),2次DOM操作

Vue vs React Diff

特性 Vue React
同层比较 ✅ ✅
Key ✅ 必须 ✅ 必须
算法 双端/最长递增子序列 右侧遍历
移动优化 最小移动 按需移动
复杂度 O(n) O(n)

Vue3 的优化

  1. 静态提升:静态节点只创建一次
  2. PatchFlag:编译时标记动态节点,Diff 时只比较动态部分
  3. Block Tree:将动态节点拍平为数组,跳过静态节点
  4. 缓存事件处理器:内联函数只创建一次
// 编译后的渲染函数带有 PatchFlag
createVNode('div', { class: 'static' }, 'hello', PatchFlags.TEXT)
// Diff 时只比较 text,跳过 class

同分类其他题目