第 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 都更快。

相关推荐
Amumu1213811 分钟前
NodeJs介绍
前端·node.js
咧咧小侠13 分钟前
Windows Codex 连接 Chrome 失败:一次 nodeRepl.fetch 报错排查记录
前端·chrome
Eider199815 分钟前
大模型输出格式幻觉解决思路
开发语言·前端·javascript
广州智造15 分钟前
Radioss时间步长(Time Step)
前端·设计·cad·建模·cae·radioss
丑陋小蚊子31 分钟前
网申简历附件太大,先换模板还是压缩 PDF?
面试·求职招聘·大学生·简历·简历下载
志尊宝36 分钟前
Vue3 零基础每日笔记(085):项目上线前 Checklist——环境变量、报错监控、安全自查
前端·javascript·笔记·安全·信息可视化·echarts
朱涛的自习室1 小时前
我让 Gemini 4 当高管、DeepSeek 当员工,开了一家软件公司(Day 1)
android·前端·人工智能
志尊宝1 小时前
Vue3 零基础每日笔记(088·完结):从零到一——一个完整 Vue3 项目的成长复盘
前端·javascript·vue.js·笔记·ecmascript·#vue.js
deli0071 小时前
加一台机器,为什么只有 1/N 的 key 要搬家?一致性哈希实测
前端
兔子零10241 小时前
FastAPI 零基础入门教程:写过 Node.js,就能轻松学会 Python 后端开发(一)
前端·后端·python