Vue响应式和Diff
Vue 的响应式系统(Reactivity)和 Diff 算法解决的是两个不同的问题。
- 响应式系统: 知道数据什么时候发生变化,以及哪些组件需要更新。
- Diff 算法: 在组件更新时,判断新旧虚拟 DOM 有哪些区别,从而尽量减少真实 DOM 操作。
一、先看一个例子
1 | |
当你点击按钮时:
1 | |
响应式系统发现 count 改变了,于是通知依赖它的组件需要更新。
但是这里有一个问题:
响应式系统知道 count 变化了,不代表它直接知道真实 DOM 中具体哪个文本节点需要修改。
因此 Vue 会重新执行组件的渲染逻辑,生成新的虚拟 DOM,并通过更新算法处理变化。
二、响应式和 Diff 的分工
Vue 3 组件更新流程(简化示意)
假设更新前后的虚拟 DOM 分别是:
旧虚拟 DOM:
1 | |
新虚拟 DOM:
1 | |
Diff 比较后发现:
| 元素 | 是否变化 | 操作 |
|---|---|---|
div |
否 | 保留 |
h1 |
否 | 保留 |
p |
是 | 更新文本 |
button |
否 | 保留 |
最终只需要更新计数文本,不必重新创建整个 DOM。
三、既然知道 count 变化了,为什么不直接更新 p?
这才是问题的核心。
实际上,Vue 3 已经在尽可能这样做了。
Vue 3 不只是依靠传统的虚拟 DOM Diff,还使用了编译时优化。
例如:
Vue 编译器可以分析出:
<h1>是静态内容。<p>包含动态文本。- 只有
<p>中的文本需要关注变化。
Vue 3 使用 Patch Flags(补丁标记)、静态提升等技术,让更新过程尽可能跳过静态部分。
所以 Vue 3 并不是每次都完整比较整棵虚拟 DOM 树。
但为什么还需要 Diff?
因为组件可能存在复杂的结构变化:
这里不仅仅是文本发生变化,还可能出现:
p被button替换。- 列表新增元素。
- 列表删除元素。
- 列表元素顺序变化。
这些场景需要 Vue 判断如何复用、移动、创建或删除 DOM 节点。
响应式系统本身不负责这些结构上的更新决策。
四、总结
| 对比 | 响应式系统 | Diff 算法 |
|---|---|---|
| 解决问题 | 什么时候需要更新 | 更新哪些 DOM |
| 关注对象 | 响应式数据和依赖 | 新旧虚拟 DOM |
| 核心技术 | Proxy、依赖追踪、effect | 节点比较、Patch |
| 主要作用 | 触发更新 | 尽量减少 DOM 操作 |
记住一句话:
响应式系统负责发现变化,Diff 算法负责处理渲染结果的差异,而 Vue 3 的编译器负责帮助它们减少不必要的工作。
Vue 3 为什么使用虚拟 DOM,而 SolidJS 等框架可以使用细粒度响应式直接更新 DOM,几乎不需要虚拟 DOM Diff?
这正好能进一步解释这个问题。
Vue响应式和Diff
https://umeshu.cn/2021/09/13/Front/Vue响应式和Diff/
