Vue2/3 与 React Diff 算法原理及差异
一、前言
你将从本文了解到:
Vue2/Vue3/React diff算法的差异,以及各自diff算法的核心思路。
二、Diff 算法前置基础
1. 什么是 Diff 算法
当数据发生变化时,同层级对比新旧Dom树,找出最小差异,只更新变化的 DOM,不整棵树重绘,这个对比过程就是Diff 算法。
2. Key 的作用
Key 是节点唯一标识,帮助框架识别新旧节点是否为同一个节点,实现节点复用,这也是为什么不推荐index作为key的原因。
三、Vue2 双端比较
1. 核心思路
维护四个指针:旧头、旧尾、新头、新尾从两头向中间同时比对,四种匹配逻辑:
old头new头 old尾new尾 old头new尾 old尾new头,
命中任意一种,直接移动指针或移动 DOM 节点。
2. 四种都不匹配如何处理
通过 key 生成映射表,用新头 key 去旧列表查找:
1. 如果找到可复用节点,移动到旧列表尾部复用,实现匹配。
2. 如果没找到,创建新 DOM 插入尾部。
3. Vue2 双端比较优势
- 首尾微调场景速度极快
- 简单乱序场景适配性好
4. 缺点
大规模乱序、随机打乱列表时,无法算出最优解,DOM 移动操作冗余较多。
四、Vue3 双端 + LIS 最长递增子序列
1. 整体执行流程
先双端快速匹配,后 LIS 优化乱序
- 先进行首尾双端比对,把顺序没变的首尾节点快速过滤,收缩指针范围;
- 剩下中间乱序节点,开启 LIS 最长递增子序列优化;
- 生成新列表可复用节点对应的旧索引数组;
- 求出最长递增子序列,序列内节点原地不动,只移动不在序列中的节点。
2. LIS 解释
即在乱序节点中,找到递增的队列:
old队列: 123456 new队列: 143625
其中new队列里找到146作为最长递增子序列,然后移动3 2 5。
3. Vue3 Diff 优势
- 继承双端快速匹配优点,常规场景开销极低
- 乱序重排场景通过 LIS 实现最少 DOM 移动
4. 缺点
极简顺序场景,比 Vue2 多一点 LIS 计算开销,但其实也还好。
五、React 仅右移
1. 核心策略
单向从左到右遍历 + lastIndex 标记。
2. 仅右移规则
React 只会把节点向右插入,不会主动把后面的节点向左挪动。lastIndex是一个比较依据,不属于新旧队列指针。
遍历过程是这样的:
- 如果之前没有找到过新节点对应的 oldIndex,则通过 Map 获取 oldIndex,进入比较阶段;
- 如果 Map 中不存在该新节点的 oldIndex,视为新增节点,创建并插入到已渲染队列末尾;
- 如果之前找到过新节点对应的 oldIndex,进入比较阶段;
比较阶段:
- oldIndex >= lastIndex ,顺序正常,更新 lastIndex,复用该节点,追加到已渲染队列末尾;
- 若 oldIndex < lastIndex ,判定为需要右移,不更新 lastIndex,复用该节点,追加到已渲染队列末尾;
3. React Diff + Fiber 架构
把递归 Diff 拆分为 Fiber 链表小任务,利用时间切片,空闲时执行 Diff。
高优先级交互任务可插队,不会阻塞主线程,适合大型复杂项目,保证页面流畅度。
4. React Diff 优势
- 算法较为简单,单向遍历逻辑清晰易维护
- 适配 Fiber 时间切片,可中断调度
5. 缺点
乱序、倒序、头部插入场景,DOM 冗余操作多,性能较差。
六、总结
Vue2 采用双端比较,靠四指针头尾匹配,匹配失败就把可复用节点挪到旧列表尾部复用,只玩头尾。
Vue3 先双端精简首尾,再对中间乱序节点用LIS 最长递增子序列,LIS 节点原地不动,只移动其余节点,实现最少 DOM 移动。
React 采用单向遍历 + lastIndex 仅右移策略,算法简单,乱序开销大;依靠 Fiber 可中断调度,不阻塞主线程,更适合大型项目。
更多推荐



所有评论(0)