vue diff实现
Vue 的 Diff 算法实现
Vue 的虚拟 DOM Diff 算法(即 patch 过程)采用双端比较策略,通过高效比对新旧虚拟节点来最小化 DOM 操作。以下是核心实现逻辑:
双端比较策略
Diff 算法会同时从新旧子节点的头部和尾部开始比对,分为四种情况按顺序尝试匹配:
- 旧头 vs 新头:若节点相同,直接复用 DOM,移动指针至下一项。
- 旧尾 vs 新尾:若节点相同,直接复用 DOM,移动指针至前一项。
- 旧头 vs 新尾:若节点相同,将旧头节点移动到旧尾之后。
- 旧尾 vs 新头:若节点相同,将旧尾节点移动到旧头之前。
若以上均不匹配,则通过 key 查找可复用节点。
Key 的作用
为节点设置唯一的 key 能帮助算法快速定位可复用节点。若找到相同 key 的节点,则移动 DOM 到正确位置;若无匹配,则创建新节点。
// 示例:通过 key 映射旧节点位置
const oldKeyToIdx = {
'key1': 0,
'key2': 1
};
处理剩余节点
- 旧节点有剩余:删除多余 DOM。
- 新节点有剩余:创建并插入新 DOM。
// 删除旧节点
while (oldStartIdx <= oldEndIdx) {
removeVnode(oldCh[oldStartIdx++]);
}
// 添加新节点
while (newStartIdx <= newEndIdx) {
createElm(newCh[newStartIdx++], parentElm);
}
优化策略
- 同级比较:仅对比同层节点,不跨层级,复杂度 O(n)。
- 原地复用:相同节点复用 DOM,仅更新属性/内容。
- 批量更新:将 DOM 操作合并到异步队列,减少重排次数。
核心代码逻辑
Vue 的 patch 函数通过递归比对节点,核心实现在 src/core/vdom/patch.js 中:

function updateChildren(parentElm, oldCh, newCh) {
let oldStartIdx = 0, newStartIdx = 0;
let oldEndIdx = oldCh.length - 1, newEndIdx = newCh.length - 1;
// ...双端比较逻辑
}
注意事项
- 避免索引作为 key:可能导致渲染错误或性能下降。
- 减少动态节点变化:稳定结构可提升 Diff 效率。
- 列表渲染时优先用 key:确保节点移动而非销毁重建。






