vue3的diff算法图解

203 阅读1分钟

场景介绍 现在有oldVNode和newVNode两个虚拟node,数据结构如下;要求用diff算法更新newVNode到oldVNode上。下面对三种diff分别介绍

const oldVNode = {
    type: 'div',
    children: [{
            type: 'p',
            children: '1',
            key: 1
        },
        {
            type: 'p',
            children: '2',
            key: 2
        },
        {
            type: 'p',
            children: '3',
            key: 3
        },
    ]
}
const newVNode = {
    type: 'div',
    children: [{
            type: 'p',
            children: '4',
            key: 3
        },
        {
            type: 'p',
            children: '5',
            key: 2
        },
        {
            type: 'p',
            children: '6',
            key: 1
        },
    ]
}

简单diff

执行过程 1: 从newVnode的第一个开始,找oldVnode里面有没有能复用的,有就先打patch(复用dom,更新内部内容),没有就代表要挂载。

2:判断lastindex是否大于j,大于代表需要移动,移动到上一个节点的下面,小于则不需要移动,更新lastindex.

图解

简单diff流程.jpg

双端diff

执行过程 1:采用四个端点记录oldVNode头尾和newVNode的头尾,同时对于四个index

2:依次进行头头比较、头尾比较、尾头比较和尾尾比较,找到能复用旧直接复用,注意头尾和尾头相同时要移动,否则对当前端点进行简单diff;直到有一方的startindex>endindex结束,

3:另外一方的startIndex可能还小于endIndex;说明有多余的dom节点,旧的就删除,新的旧挂载

图解:

双端diff.jpg

快速diff

  1. 先进行头头和尾尾的复用
  2. 已经处理过的不管,未处理的新建起点j和结束点oldEnd,newEnd
  3. 对新的节点建立sorce数组,代表在旧数组中的位置,-1表示没有要新挂载
  4. 对新节点建立索引表,key为vnode的key,value为在新节点中的下标
  5. 打patch,用索引表打patch
  6. 计算最长递增子序列表示不需要移动的节点
  7. 更新节点并移动

快速diff.jpg