Vue 虚拟 DOM 和 diff 算法的原理是什么?
请说明 Vue 的虚拟 DOM 如何工作,以及其 diff 算法(双端比较)的核心流程。
回答
苦行僧
虚拟 DOM(Virtual DOM):用 JavaScript 对象描述真实 DOM 结构的树形数据结构。
// VNode 结构
{
tag: 'div',
props: { class: 'container' },
children: [
{ tag: 'span', props: {}, children: 'Hello' }
]
}
为什么要用虚拟 DOM:
- 最小化真实 DOM 操作(昂贵)
- 跨平台渲染(DOM/Canvas/SSR/原生)
- 提供声明式编程能力
Vue diff 算法(双端比较):
- 对两个同层 VNode 数组进行比较
- 核心:头尾指针对比,尽量减少移动
流程(源码 patchChildren):
旧: [A, B, C, D] 新: [B, A, D, E]
↑oldStart ↑newStart
↓oldEnd ↓newEnd
Step 1: 比较 oldStart 和 newStart → A vs B ❌
Step 2: 比较 oldEnd 和 newEnd → D vs E ❌
Step 3: 比较 oldStart 和 newEnd → A vs E ❌
Step 4: 比较 oldEnd 和 newStart → D vs B ❌
Step 5: 用 key 查找新节点在旧节点中的位置
最终:B 移动到头部,D 删除,E 新增
优化策略:
- 同类型比较:标签名 + key 决定是否复用
- 静态标记(PatchFlags):Vue 3 模板编译时标记动态绑定的位置(class/text/props),diff 时只检查标记过的节点
- Block Tree:跳过静态结构,只 diff 动态节点
Vue 3 vs React diff:
- Vue 3:模板编译优化(PatchFlags + Block Tree),运行期只需对比动态节点
- React:JSX 无编译优化,运行期完全 diff
- Vue 3 性能通常优于 React(同等工作量下)