【VUE】vue2/vue3的Diff算法

162 阅读1分钟

1. 简介

Diff算法是一种通过同层的树节点进行对比的高效算法。例如我们提交 prmr时,会对比当前代码的改动。而Vuediff算法是对vdom的一种对比。

Diff的整体策略: 深度优先,同层渲染。

2. Vue2 Diff

2.1 单节点对比

/*
  判断两个VNode节点是否是同一个节点,需要满足以下条件
  key相同
  tag(当前节点的标签名)相同
  isComment(是否为注释节点)相同
  是否data(当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息)都有定义
  当标签是<input>的时候,type必须相同
*/
function sameVnode (a, b) {
  return (
    a.key === b.key &&
    a.tag === b.tag &&
    a.isComment === b.isComment &&
    isDef(a.data) === isDef(b.data) &&
    sameInputType(a, b)
  )
}

2.2 多节点对比

双端比较:

while循环2个列表,利用四个指针指向双列表的前后,假设一致则复用,不一致则下标+1继续进行对比。

1.oldStartIndex.key === newStartIndex.key

2.oldStartIndex.key === newEndIndex.key

3.oldEndIndex.key === newStartIndex.key

4.oldEndIndex.key === newEndIndex.key

5.查找旧列表的缓存映射

5.1`key`相同则复用,设置`oldNode = undefined,` 移动`newStartIndex`

5.2 找不到则新建一个放在最前面,移动`newStartIndex`

6.循环走完了

6.1 `oldEndIndex` < `oldStartIndex` 判断新列表是否还有节点,有的话则按位置插入节点就行。

6.2 `newEndIndex` < `newStartIndex` 判断旧列表是否还有节点,有的话则删除

3. Vue3 Diff

1.前-前对比

2.后-后对比

3.最长递增子序列: 较少DOM的移动、达到最小的DOM操作

例如数据 [3, 5, 7, 1, 2, 8]的最长递增子序列就是[3, 5, 7, 8]

例子:

1.前-前对比 -> A B
2.后-后对比 -> G
3. 剩余节点 F C D E H

通过 newIndexToOldIndexMap 拿到oldChildren 中对应的 index [5, 2, 3, 4, -1](-1表示没有,要新增)

计算最长递增子序列 得出[2, 3, 4]表示 C D E 不需要变化

剩余的节点,根据index进行新增、删除、移动