1. 是什么

DOM diff 就是对比两棵虚拟 DOM 树的算法。当组件变化时,会 render 出一个新的虚拟 DOM树, diff 算法对比新旧虚拟 DOM 树之后,得到一个 patch, 然后 React 用 patch 来更新真实 DOM。

2. 怎么做

a. 首先对比两棵树的根节点

  • 如果根节点的类型改变了,比如 div 变成了 p, 那么直接认为整棵树都变了,不再对比子节点。此时直接删除对应的真实 DOM 树,创建新的真实 DOM 树。
  • 如果根节点的类型没变,就看看属性变了没有
    • 如果没变,就保留对应的真实节点
    • 如果变了,就只更新该节点的属性,不重新创建节点。
      • 更新 style 时,如果多个 css 属性只有一个改变了,那么 React 只更新改变的

b. 然后同时遍历两棵树的子节点,每个节点的对比过程同上。

  • 情况一 ```html
    • A
    • B
  • A
  • B
  • C
React 依次对比A-A, B-B, 空-C, 发现 C 是新增的,最终会创建真实 C 节点插入页面。 - 情况二html
  • B
  • C
  • A
  • B
  • C
React 对比 B-A,会删除 B 文本新建 A 文本;对比 C-B,会删除 C 文本,新建 B 文本;(注意,并不是边对比边删除新建,而是把操作汇总到 patch 里再进行 DOM 操作。)对比空-C,会新建 C 文本。 你会发现其实只需要创建 A 文本,保留 B 和 C 即可,为什么 React 做不到呢?<br />因为 React 需要你加 key 才能做到:html
  • B
  • C

  • A
  • B
  • C
``` React 先对比 key 发现 key 只新增了一个,于是保留 b 和 c,新建 a。
以上是 React 的 diff 算法

3. 双端交叉对比

vue 的 DOM diff 算法使用的是双端交叉对比
将新旧虚拟 DOM 树各自有共同父亲的子节点分别存入两个数组,而且有四个变量充当指针分别指到两个数组的头尾.
重复下面的对比过程,直到两个数组中任一数组的头指针超过尾指针,循环结束 :

  • 头头对比: 对比两个数组的头部,如果找到,把新节点patch到旧节点,头指针后移
  • 尾尾对比: 对比两个数组的尾部,如果找到,把新节点patch到旧节点,尾指针前移
  • 旧尾新头对比: 交叉对比,旧尾新头,如果找到,把新节点patch到旧节点,旧尾指针前移,新头指针后移
  • 旧头新尾对比: 交叉对比,旧头新尾,如果找到,把新节点patch到旧节点,新尾指针前移,旧头指针后移
  • 利用key对比: 用新指针对应节点的key去旧数组寻找对应的节点,这里分三种情况,当没有对应的key,那么创建新的节点,如果有key并且是相同的节点,把新节点patch到旧节点,如果有key但是不是相同的节点,则创建新节点

4. React DOM diff 和 Vue DOM diff 的区别:

  1. React 是从左向右遍历对比,Vue 是双端交叉对比。
  2. React 需要维护三个变量,Vue 则需要维护四个变量。
  3. Vue 整体效率比 React 更高,举例说明:假设有 N 个子节点,我们只是把最后子节点移到第一个,那么
    1. React 需要进行借助 Map 进行 key 搜索找到匹配项,然后复用节点
    2. Vue 会发现移动,直接复用节点