Vue 2与Vue3.diff算法比对

本文聚焦Diff算法核心原理、执行步骤、核心源码实现与更新机制对比。

一、前置共识:Diff在整个更新机制中的位置

Vue的更新机制是一条完整链路,Diff只是其中一环,先把整条链路讲清楚:

数据变化 → 触发响应式通知 → 组件重新render → 生成新VNode树 → Diff对比新旧VNode → Patch更新真实DOM

核心原则:同层比较,不跨层。完整树对比复杂度O(n³)不可用,Vue和React都做了同层对比的工程妥协,将复杂度降至O(n)。Diff算法最复杂的场景,就是同层子节点列表的对比,这也是Vue2和Vue3差异最大的地方。


二、Vue2 Diff算法:双端比较法(双指针)

2.1 算法原理

Vue2采用双端比较策略,用四个指针分别指向新旧列表的首尾,每一轮优先对比两端的节点,命中则直接复用并移动指针;四次都没命中时,再用新列表头部节点去旧列表中遍历查找。

2.2 四个核心指针

旧列表:oldStartIdx → ... ← oldEndIdx 新列表:newStartIdx → ... ← newEndIdx

2.3 执行步骤(逐轮循环)

每一轮循环按以下顺序做4次比较:

第1次:旧头 vs 新头

  • 相同:两个头指针都后移一位,进入下一轮
  • 不同:继续下一次比较

第2次:旧尾 vs 新尾

  • 相同:两个尾指针都前移一位,进入下一轮
  • 不同:继续下一次比较

第3次:旧头 vs 新尾

  • 相同:旧头节点移动到旧尾后面,旧头指针后移,新尾指针前移
  • 不同:继续下一次比较

第4次:旧尾 vs 新头

  • 相同:旧尾节点移动到旧头前面,旧尾指针前移,新头指针后移
  • 不同:进入兜底查找

兜底:遍历查找

  • 拿新头节点的key,去旧列表中遍历找相同key的节点
  • 找到:把该节点移动到旧头前面,旧列表对应位置标记为null,新头指针后移
  • 没找到:新建节点插入到旧头前面,新头指针后移

循环终止条件:旧列表或新列表的头指针超过尾指针(有一方先遍历完)

收尾处理

  • 旧列表先走完:新列表剩余的节点全部新增
  • 新列表先走完:旧列表剩余的节点全部删除

2.4 流程图

<