一、什么是虚拟 DOM(Virtual DOM)
虚拟 DOM本质上是:
用 JavaScript 对象描述真实 DOM 结构。
真实 DOM 是浏览器中的节点结构,而虚拟 DOM 是一个 JS 对象树。
例如一个简单的 HTML:
<div id="app">
<p>Hello</p>
</div>
虚拟 DOM 可能是这样的:
{
type: "div",
props: { id: "app" },
children: [
{
type: "p",
children: ["Hello"]
}
]
}
特点:
- 用 JS 对象表示 DOM
- 可以在内存中计算变化
- 最后再一次性更新真实 DOM
二、为什么需要虚拟 DOM
直接操作真实 DOM 的问题:
1️⃣ DOM 操作很慢
2️⃣ 频繁更新会触发 重排(reflow)和重绘(repaint)
3️⃣ 手动优化成本高
所以框架做了这件事:
状态变化
↓
生成新的虚拟DOM
↓
Diff算法比较新旧虚拟DOM
↓
只更新变化部分
↓
更新真实DOM
核心思想:
最小化 DOM 操作
三、Diff 算法是什么
Diff 算法就是:
比较新旧虚拟 DOM 树,找出变化的地方。
然后只更新变化的节点。
流程:
old VDOM
↓
Diff比较
↓
找出变化节点
↓
Patch更新真实DOM
四、Diff 算法的三大核心策略
为了保证效率,框架做了很多限制。
1 同层比较(Tree Diff)
只比较 同一层节点,不跨层比较。
例如:
旧:
A
└ B
新:
B
└ A
不会去深度寻找,只会认为:
删除A
新增B
这样复杂度从:
O(n³)
降到:
O(n)
2 不同类型节点直接替换
例如:
旧:
<div>
新:
<p>
直接删除旧节点,创建新节点。
不会继续比较子节点。
3 Key 优化列表 Diff
在列表渲染中:
{list.map(item => (
<li key={item.id}>{item.name}</li>
))}
key 的作用:
帮助框架识别节点身份
例如:
旧列表:
A B C D
新列表:
B C D A
如果没有 key:
全部重新渲染
如果有 key:
移动A到最后
性能会高很多。
五、React 的 Diff 过程
在 React 中大致流程:
state变化
↓
render()
↓
生成新的Virtual DOM
↓
Diff算法比较旧VDOM
↓
生成Patch
↓
更新真实DOM
React 16 之后还有:
Fiber 架构
特点:
- 可中断渲染
- 优先级调度
- 更流畅的 UI 更新
六、Vue 的 Diff
在 Vue 中:
Vue3 使用的是:
快速 Diff(Fast Diff)
优化包括:
- 双端比较
- 最长递增子序列(LIS)
列表移动性能更好。
七、经典面试总结(建议背)
什么是虚拟 DOM?
虚拟 DOM 是用 JavaScript 对象描述真实 DOM 结构,通过 Diff 算法对比新旧虚拟 DOM,计算最小更新,然后同步到真实 DOM,从而提高页面渲染性能。
Diff 算法优化策略
1️⃣ 同层比较
2️⃣ 不同类型直接替换
3️⃣ key 优化列表更新
八、简单流程图(非常好记)
数据变化
↓
生成新VDOM
↓
Diff算法
↓
找出变化
↓
更新真实DOM