虚拟DOM和Diff算法?

0 阅读2分钟

一、什么是虚拟 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)

只比较 同一层节点,不跨层比较。

例如:

旧:

AB

新:

BA

不会去深度寻找,只会认为:

删除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