Vue Diff 算法源码过程梳理

70 阅读1分钟

1. 比较顺序

Diff 算法在比较两个节点的时候,只会在同层进行比较,而不会跨层比较,所以可以使用双端交叉算法。

2. 算法概述

2.1 含有类型

Vue 中含有的类型一般为如下类型,而 React 包含的类型为 tag, props, children;

{
  "tag": "xxx",
  "key": "xxx",
  "elm": "xxx",
  "text": "xxx",
  "data": {...},
  "children": [{...}, ...]
}

2.2 比较根节点

首先使用 patch(oldVnode, vnode) 方法比较两个根节点:

  • 新节点不存在,直接删除整个旧节点;
  • 新节点存在,旧节点不存在,新增整个新节点;
  • 判断它们的 tag 类型是否相同,相同则仅更新属性即可;
  • 若二者皆为文本类型,若文本信息不同,则更新文本节点;

2.3 比较孩子节点

  • vnode 的孩子节点不存在,oldVnode 孩子节点存在,则直接删除整个孩子节点;若孩子节点为文本类型,则清空文本;
  • vnode 孩子节点存在,oldVnode 孩子节点不存在,直接新增整个孩子节点;
  • 二者都存在,使用 updateChildren(elm, oldCh, ch) 比较孩子节点,使用双端交叉算法比较
    • 使用四个指针:oldStartIdx、oldEndIdx、newStartIdx、newEndIdx;
    • 依次进行头头比较、尾尾比较、前头后尾、前尾后头;若相同,则前指针后移,后指针前移;
    • 若发现上述四个均不相同,则使用 key 进行比较。将 oldVnode 中的 key -> index 保存在 Map 中,然后使用 vnode 中的 key 查找,若找到,则将找到的 oldVnode 中对应的 index 处的内容置为 undefined,然后指针移动,直到 oldStartIdx >= oldEndIdx 或者 newStartIdx >= newEndIdx,这时删掉旧节点,增添新节点即可。

参考文章:juejin.cn/post/697162…