vue3----Diff算法解析---最长递增子序列

81 阅读3分钟

diff分为5步:

  • 自前向后的对比:会依次获取相同下标的oldChild和newChild
    • 如果oldChild和newChild为相同的VNode,则直接通过patch进行补丁即可
    • 如果oldChild和newChild为不相同的VNode,则会跳出循环
    • 每次处理成功,则会自增i标记,表示:自前向后已处理过的节点数量
  • 自后向前的对比
  • 新节点多于旧节点,需要挂载
  • 旧节点多于新节点,需要卸载
  • 乱序(最长递增子序列)

最长递增子序列

定义:在一个给定的数值序列中,找到一个子序列,使这个子序列元素的数值依次递增,并且子序列的长度尽可能的大 作用:减少移动的次数,提升性能

动态规划----》解最值问题

  • 备忘录:(DP Table)

解决方案---二分查找优化

const nums = [10,2,5,3,7,18]
function lengthOfLIS (nums:number[]):number {
  
    if (nums.length <= 1) {
        return nums;
    }
    let tail = [nums[0]];//存放最长上升子序列数组
    for (let i = 0; i < nums.length; i++) {
       if (nums[i] > tail[tail.length - 1]) {
           tail.push(nums[i]);//当nums中的元素比tail中的最后一个大时 可以放心push进tail
        } else {//否则进行二分查找
            let left = 0;
            let right = tail.length - 1;
            while (left < right) {
                let mid = (left + right) >> 1;//>>运算符执行有符号右移位运算
                if (tail[mid] < nums[i]) {
                    left = mid + 1;
                } else {
                    right = mid;
                }
            }
            tail[left] = nums[i];//将nums[i]放置到合适的位置,此时前面的元素都比nums[i]小
        }
    }
    return tail.length;
}

patchKeyedChildren方法究竟做了什么?

第一步的事情就是从头开始寻找相同的vnode,然后进行patch,如果发现不是相同的节点,那么立即跳出循环。

第二步从尾开始同前diff

如果老节点是否全部patch,新节点没有被patch完,创建新的vnode

如果新节点全部被patch,老节点有剩余,那么卸载所有老节点

最长稳定序列

总结

从头对比找到有相同的节点 patch ,发现不同,立即跳出。 如果第一步没有patch完,立即,从后往前开始patch ,如果发现不同立即跳出循环。 如果新节点大于旧节点数 ,对于剩下的节点全部以新的vnode处理( 这种情况说明已经patch完相同的vnode )。 对于旧节点大于新节点的情况 , 对于超出的节点全部卸载 ( 这种情况说明已经patch完相同的vnode )。 不确定的元素( 这种情况说明没有patch完相同的vnode ) 与 3 ,4对立关系。 1 把没有比较过的新的vnode节点,通过map保存 记录已经patch的新节点的数量 patched 没有经过 path 新的节点的数量 toBePatched 建立一个数组newIndexToOldIndexMap,每个子元素都是[ 0, 0, 0, 0, 0, 0, ] 里面的数字记录老节点的索引 ,数组索引就是新节点的索引。 开始遍历老节点 ① 如果 toBePatched新的节点数量为0 ,那么统一卸载老的节点 ② 如果,老节点的key存在 ,通过key找到对应的index ③ 如果,老节点的key不存在 1 遍历剩下的所有新节点 2 如果找到与当前老节点对应的新节点那么 ,将新节点的索引,赋值给newIndex ④ 没有找到与老节点对应的新节点,卸载当前老节点。 ⑤ 如果找到与老节点对应的新节点,把老节点的索引,记录在存放新节点的数组中, 1 如果节点发生移动 记录已经移动了 2 patch新老节点 找到新的节点进行patch节点 遍历结束

image.png