第 28 题:Vue3 的 Diff 算法核心原理(双端 Diff、PatchFlags、Block Tree、静态提升)

第 27 题:Vue3 的 Diff 算法核心原理(双端 Diff、PatchFlags、Block Tree、静态提升)

我会按照结构:
核心回答 → 深度讲解 → 动画级别示意 → PatchFlags & 静态提升 → 面试官追问 → 高分总结


一、核心回答(面试官最想听)

Vue3 的 Diff 算法是基于 双端对比 + 最长递增子序列(LIS)优化 + 静态提升 + block tree + patchFlags 的。

比 Vue2 快的原因:

  1. 静态节点跳过 diff
  2. PatchFlags 减少不必要对比
  3. block tree 限制 diff 范围
  4. 优化后的双端 Diff + LIS
  5. 模板编译阶段极大地减少了运行时工作量

二、深度原理(深入讲,高分)


1️⃣ Vue3 Diff = "双端 Diff + LIS"

Vue3 的核心 Diff 逻辑如下:

第一阶段:从头开始比对(前端指针)

如果新旧头节点是相同 key,就 patch 并移动:

css 复制代码
旧:[A B C D]
新:[A B E C D]

从头开始:
A → match
B → match
遇到 C / E 不同,停止

第二阶段:从尾开始比对(后端指针)

css 复制代码
旧:[A B C D]
新:[A B E C D]

从尾开始:
D → match

第三阶段:处理中间乱序部分(核心:LIS)

只对中间这一段做 Diff:

css 复制代码
旧:[C]
新:[E C]

Vue3 会:

  • 建立 key → newIndex 的映射
  • 找出新列表中的最长递增子序列(LIS)
  • 其他节点移动或新建

为什么用 LIS?

保持最长不动序列,减少 DOM 移动次数,这是最优移动策略。


2️⃣ PatchFlags(编译器给每个节点打标签)

PatchFlags 是 Vue3 性能飞越的核心。

例如:

css 复制代码
<div :class="theme">{{ msg }}</div>

编译器会这样标注:

  • :class 是动态绑定 → PatchFlag: CLASS
  • msg 是动态文本 → PatchFlag: TEXT

运行时只 patch 有变化的部分

⚡ 性能极强,因为跳过所有静态节点。


3️⃣ 静态提升(static hoisting)

Vue3 会把模板中永远不会变的 DOM 结构提前提升到外部:

css 复制代码
<div><span>Hello</span></div>

静态提升后:

ini 复制代码
const _hoisted_1 = h("span", "Hello")

每次渲染:

  • 静态 vnode 复用
  • 不重新创建不 diff vnode

Vue2 每次 render 都重新创建所有 vnode → 低效


4️⃣ Block Tree(Vue3 的革命性设计)

Vue3 把组件拆成一个个 block,每个 block 只 diff 自己内部的动态节点列表。

示例:

css 复制代码
<div>
  <p>静态</p>
  <p>{{msg}}</p>
</div>

Vue 会生成类似结构:

scss 复制代码
Block root: only tracks [p(msg)]

静态部分完全跳过。

Diff 范围更小,性能更高。


5️⃣ 为什么 Vue3 比 React18 更快?

因为 Vue3 使用 模板编译提前做大量优化

  • 静态提升
  • PatchFlags
  • Block Tree
  • 编译期确定最小更新单元

React 是纯运行时,不知道谁是动态的,每次 render 都 diff 全量子树。


三、代码示例:Diff 执行过程可视化动画(面试官会点头)

旧节点:

css 复制代码
A B C D E F

新节点:

css 复制代码
A C E B D G F

1. 双端比对阶段:

ini 复制代码
A = A  → ok
F = F  → ok

中间区域:

旧:B C D E

新:C E B D G

2. 建立映射:

css 复制代码
C → 0
E → 1
B → 2
D → 3
G → 4

3. 算 LIS → [0,1,3] = C, E, D

保持不动的节点:C、E、D

要移动的:B

要新增的:G


四、面试官追问 & 高分回答


❓1. Vue3 Diff 与 Vue2 Diff 的区别?

你可以直接这样答(高分):

Vue2

  • 全量双端 diff
  • 无 PatchFlags
  • 无静态提升
  • 无 block tree

Vue3

  • 更智能的 diff:双端 + LIS
  • 编译器优化:PatchFlags + static hoisting
  • block tree:减少 diff 范围

总结:Vue2 是"纯运行时 diff",Vue3 是"编译 + 运行时混合优化 diff"。


❓2. 为什么需要最长递增子序列?

为了减少 DOM 移动次数。

没有 LIS:

  • 每个节点都要移动 → 最坏 O(n²)

有 LIS:

  • 移动最少,趋近优化到 O(n log n)

❓3. 什么情况下 Vue 不用 Diff?

以下情况直接复用:

  • 静态节点
  • patchFlags 标识完全静态的部分
  • v-once(只渲染一次)
  • keyed children 未发生任何动态变化

❓4. key 的作用是什么?

key 是 diff 的灵魂,让节点可复用、有身份。

key 不唯一会导致:

  • patch 错乱
  • 意料之外的 DOM 复用
  • input 数据错位

五、高分总结(背下来能打工地级别)

Vue3 的 diff 是优化后的双端 diff + LIS 最长递增子序列算法,并结合编译器的 PatchFlags、静态提升、Block Tree,大幅减少 vnode 创建数量和 diff 范围,是目前前端框架中最激进的运行 + 编译混合优化方式,比 Vue2 和 React 都更快。

相关推荐
沐雪架构师1 分钟前
大模型Agent面试精选题(第五辑)-Agent提示词工程
java·面试·职场和发展
karshey15 分钟前
【前端】sort:js按照固定顺序排序
开发语言·前端·javascript
MyBFuture16 分钟前
索引器实战:对象数组访问技巧及命名空间以及项目文件规范
开发语言·前端·c#·visual studio
IT_陈寒26 分钟前
Redis性能提升50%的7个实战技巧,连官方文档都没讲全!
前端·人工智能·后端
打小就很皮...28 分钟前
React 富文本图片上传 OSS 并防止 Base64 图片粘贴
前端·react.js·base64·oss
咬人喵喵36 分钟前
告别无脑 <div>:HTML 语义化标签入门
前端·css·编辑器·html·svg
404NotFound3051 小时前
基于 Vue 3 和 Guacamole 搭建远程桌面(利用RDP去实现,去除vnc繁琐配置)
前端
咚咚咚ddd1 小时前
AI 应用开发:Agent @在线文档功能 - 前端交互与设计
前端·aigc·agent
旧梦吟1 小时前
脚本工具 批量md转html
前端·python·html5