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 → ... ← newEndIdx2.3 执行步骤(逐轮循环)
每一轮循环按以下顺序做4次比较:
第1次:旧头 vs 新头
- 相同:两个头指针都后移一位,进入下一轮
- 不同:继续下一次比较
第2次:旧尾 vs 新尾
- 相同:两个尾指针都前移一位,进入下一轮
- 不同:继续下一次比较
第3次:旧头 vs 新尾
- 相同:旧头节点移动到旧尾后面,旧头指针后移,新尾指针前移
- 不同:继续下一次比较
第4次:旧尾 vs 新头
- 相同:旧尾节点移动到旧头前面,旧尾指针前移,新头指针后移
- 不同:进入兜底查找
兜底:遍历查找
- 拿新头节点的key,去旧列表中遍历找相同key的节点
- 找到:把该节点移动到旧头前面,旧列表对应位置标记为null,新头指针后移
- 没找到:新建节点插入到旧头前面,新头指针后移
循环终止条件:旧列表或新列表的头指针超过尾指针(有一方先遍历完)
收尾处理:
- 旧列表先走完:新列表剩余的节点全部新增
- 新列表先走完:旧列表剩余的节点全部删除