Vue 2 Diff 算法

本文系统阐述 Vue 2 虚拟 DOM Diff 算法的触发时机、核心流程、同层比较策略及性能优化细节,帮助读者在源码层面理解差异更新机制。

1. 触发条件

Diff 过程在以下两种场景启动:

  • 首次挂载:组件创建阶段,无旧树,直接构建真实 DOM;
  • 响应式更新 :数据变化 → Watcher 通知 → Scheduler 微任务队列 → 批量执行 _update → 新旧 VNode 树对比。

2. 执行入口

_update(newVNode) 函数接收新生成的虚拟 DOM 根节点 ,并与组件实例上保存的旧虚拟 DOM 进行比较:

js 复制代码
function Vue() {
  const updateComponent = () => {
    this._update(this._render());
  };
  new Watcher(updateComponent);
}

若旧树为空,进入初次渲染 ;若旧树存在,进入差异对比

3. patch 核心流程

patch 函数采用 深度优先 + 同层比较 策略:

3.1 根节点判定

两节点 "相同" 的条件:

  • 标签名(tag)一致;

  • key 值一致;

  • <input> 还需 type 相同。

  • 相同节点:复用真实 DOM,执行属性更新,随后递归处理子节点;

  • 不同节点:直接销毁旧节点,按新节点递归创建真实 DOM 并挂载。

3.2 子节点对比算法

Vue 使用 双端指针 优化子节点数组比对:

css 复制代码
旧队列 [i, e1]   新队列 [j, e2]
   ↑   ↓            ↑   ↓
  • 头头匹配 → 指针右移;
  • 尾尾匹配 → 指针左移;
  • 头尾匹配 → 移动真实 DOM 到正确位置;
  • 乱序匹配 → 构建 key → index 映射,最小化移动 / 删除 / 创建次数。

通过上述策略,Diff 算法确保每一轮比较都能 最大化 DOM 复用、最小化 DOM 操作

4. 术语与语义

  • 新建元素:根据 VNode 生成真实 DOM 并挂载;
  • 销毁元素 :执行 vnode.elm.remove() 卸载 DOM;
  • 更新:仅当节点"相同"时,对比并更新属性 / 子节点;
  • 对比子节点:递归调用 patch,直至所有层级完成。

5. 性能保障

  • 最小更新:仅对差异节点执行真实 DOM 操作;
  • 批量异步:Scheduler 微任务队列合并多次变更,避免频繁重排;
  • key 优化:开发者提供稳定 key,配合双端算法降低最坏复杂度。

总结

Vue 2 的 Diff 发生在组件更新阶段,通过 patch 函数深度优先对比新旧 VNode。根节点按 tag + key 判定是否复用,子节点使用双端指针算法最小化移动操作,最终只 patch 差异节点,保证性能。

相关推荐
幼儿园技术家4 分钟前
前端如何设计权限系统(RBAC / ABAC)?
前端
前端摸鱼匠2 小时前
Vue 3 的v-bind合并行为:讲解v-bind与普通属性合并的规则
前端·javascript·vue.js·前端框架·ecmascript
REDcker2 小时前
浏览器端Web程序性能分析与优化实战 DevTools指标与工程清单
开发语言·前端·javascript·vue·ecmascript·php·js
donecoding4 小时前
一个 sudo 引发的血案:npm 全局包权限错乱彻底修复
前端·node.js·前端工程化
风骏时光牛马4 小时前
Raku正则匹配与数据批量处理实操案例
前端
nbwenren4 小时前
2026实测:Gemini 3 镜像站视觉能力实践——拍照原型图,一键生成 HTML+CSS 代码
前端·css·html
Lee川4 小时前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端
许彰午4 小时前
我手写了一个 Java 内存数据库(二):B+ 树的插入与分裂
java·开发语言·面试
jinanwuhuaguo4 小时前
(第二十九篇)OpenClaw 实时与具身的跃迁——从异步孤岛到数字世界的“原住民”
前端·网络·人工智能·重构·openclaw