Vue2 Diff和Vue 3 Diff实现及底层原理

一、一句话总览(先建立全局认知)

维度 Vue 2 Diff Vue 3 Diff
核心算法 双端比较(双指针) 最长递增子序列(LIS)
比较单位 VNode Block + 动态节点
更新策略 全量递归对比 编译期标记 + 精准更新
时间复杂度 O(n)(最坏仍有重复操作) O(n log n)
性能瓶颈 无法判断"哪些节点一定不变" 只 diff 动态节点
核心思想 运行时尽力猜 编译期提前告诉运行时

二、Vue 2 Diff:双端比较算法(运行时驱动)

1️⃣ Vue 2 的 diff 入口

复制代码
patch(oldVnode, vnode)

如果是同一节点:

复制代码
sameVnode(oldVnode, vnode)

判断条件包括:

  • key

  • tag

  • isComment

  • data 是否存在


2️⃣ 核心算法:双端指针(4 种命中)

复制代码
oldStart →        ← oldEnd
newStart →        ← newEnd

Vue 2 会依次尝试这 4 种匹配:

1️⃣ oldStart vs newStart

2️⃣ oldEnd vs newEnd

3️⃣ oldStart vs newEnd

4️⃣ oldEnd vs newStart

命中就:

  • patch

  • 移动指针

  • 移动 DOM


3️⃣ Vue 2 Diff 示例(key 很重要)

复制代码
<ul>
  <li key="a">A</li>
  <li key="b">B</li>
  <li key="c">C</li>
</ul>

更新为:

复制代码
<ul>
  <li key="b">B</li>
  <li key="a">A</li>
  <li key="c">C</li>
</ul>

Vue 2 做了什么?

  • 通过 key map 找到旧节点

  • 移动 DOM

  • patch 内容

👉 能用,但全靠运行时判断


4️⃣ Vue 2 的问题在哪里?

无法提前知道哪些节点不会变

❌ 每一层都要递归 diff

❌ 静态节点也要参与比较

❌ 复杂列表性能不稳定

Vue 2 的哲学:
"我运行时尽量少改 DOM,但我不知道哪些一定不会变"


三、Vue 3 Diff:Block Tree + LIS(编译期 + 运行时)

这是 Vue 3 真正"质变"的地方。


1️⃣ 核心思想变化(非常重要)

Vue 3 把 diff 的一半工作,提前到"编译期"做完了


2️⃣ 编译期:PatchFlags(关键)

Vue 3 编译模板时:

复制代码
<div>
  <p>{{ msg }}</p>
  <span>static</span>
</div>

会生成类似:

复制代码
createVNode("p", null, msg, PatchFlags.TEXT)

PatchFlags 告诉运行时:

Flag 含义
TEXT 只有文本可能变
CLASS class 可能变
STYLE style 可能变
PROPS props 可能变

👉 没 flag 的节点,直接跳过 diff


3️⃣ Block Tree(块级优化)

Vue 3 会把模板拆成 Block

复制代码
Block
 ├── 动态节点 1
 ├── 动态节点 2

⚠️ Block 里只存动态节点


4️⃣ 运行时 Diff:最长递增子序列(LIS)

当列表乱序时:

复制代码
[a, b, c, d] → [b, a, d, c]

Vue 3 会:

1️⃣ 通过 key 建立映射

2️⃣ 得到旧节点索引数组

复制代码
[1, 0, 3, 2]

3️⃣ 对这个数组求 最长递增子序列

复制代码
LIS = [1, 3]

👉 LIS 里的节点不用动

👉 其他节点才移动 DOM

这一步是 Vue 3 真正快的原因


5️⃣ Vue 3 Diff 过程总结

复制代码
编译期:
  模板 → PatchFlags → Block Tree

运行时:
  只 diff 动态节点
  列表用 LIS 算最少 DOM 移动

四、Vue 2 vs Vue 3 Diff 对比(面试必背)

Vue 2 Vue 3
diff 发生时机 运行时 编译期 + 运行时
静态节点 每次都比 直接跳过
列表优化 双端指针 LIS
移动次数 不确定 理论最少
key 重要性 很重要 更重要

五、底层原理一句话总结(高质量面试回答)

Vue 2 是"运行时驱动的启发式 diff"
Vue 3 是"编译期标记 + 最小化 DOM 操作的确定性 diff"


六、你这个问题在面试怎么说(示例)

Vue 2 主要使用双端指针 diff,通过 key 映射减少 DOM 操作,但所有节点都需要参与比较。

Vue 3 在编译期引入 PatchFlags 和 Block Tree,只对动态节点做 diff,列表更新时结合最长递增子序列,保证 DOM 移动次数最少,整体性能和稳定性都更好。

相关推荐
Front思6 分钟前
Vue3仿美团实现骑手路线规划
开发语言·前端·javascript
徐同保9 分钟前
Nano Banana AI 绘画创作前端代码(使用claude code编写)
前端
Ulyanov10 分钟前
PyVista与Tkinter桌面级3D可视化应用实战
开发语言·前端·python·3d·信息可视化·tkinter·gui开发
计算机程序设计小李同学10 分钟前
基于Web和Android的漫画阅读平台
java·前端·vue.js·spring boot·后端·uniapp
干前端11 分钟前
Message组件和Vue3 进阶:手动挂载组件与 Diff 算法深度解析
javascript·vue.js·算法
lkbhua莱克瓦2412 分钟前
HTML与CSS核心概念详解
前端·笔记·html·javaweb
沛沛老爹13 分钟前
从Web到AI:Agent Skills CI/CD流水线集成实战指南
java·前端·人工智能·ci/cd·架构·llama·rag
和你一起去月球14 分钟前
动手学Agent应用开发(TS/JS 最简实践指南)
开发语言·javascript·ecmascript·agent·mcp
GISer_Jing21 分钟前
1.17-1.23日博客之星投票,每日可投
前端·人工智能·arcgis
代码游侠26 分钟前
学习笔记——ARM Cortex-A 裸机开发实战指南
linux·运维·开发语言·前端·arm开发·笔记