Vue中的diff算法

1. 为什么要用Diff算法

由于在浏览器中操作DOM的代价是非常“昂贵”的,所以才在Vue引入了Virtual DOM,Virtual DOM是对真实DOM的一种抽象描述,即使使用了Virtual DOM来进行真实DOM的渲染,在页面更新的时候,也不能全量地将整颗Virtual DOM进行渲染,而是去渲染改变的部分,这时候就需要一个计算Virtual DOM树改变部分的算法了,这个算法就是Diff算法。

2. 传统的Diff算法

传统的Diff算法通过循环递归对节点进行比较,然后判断每个节点的状态以及要做的操作(add,remove,change),最后 根据Virtual DOM进行DOM的渲染。大体流程如下图(图来源):
在这里插入图片描述
传统Diff算法的复杂度为O(n^3),这个复杂度相对来说还是较高的

3. 更高效的Diff算法

使得Diff算法复杂度直接从O(n^3)降低到O(n),假设如下

  • 两个相同组件产生类似的DOM结构,不同的组件产生不同的DOM结构;

  • 对于同一层次的一组子节点,它们可以通过唯一的id进行区分。

同层比较
新的Diff算法是逐层进行比较,只比较同一层次的节点,大大降低了复杂度,具体如下图。在后面的内容中也会介绍Vue中同层节点比较的具体实现。
在这里插入图片描述
不同类型节点的比较
如果发现新旧两个节点类型不同时,Diff算法会直接删除旧的节点及其子节点并插入新的节点,这是由于前面提出的不同组件产生的DOM结构一般是不同的,所以可以不用浪费时间去比较。注意的是,删除节点意味着彻底销毁该节点,并不会将该节点去与后面的节点相比较。

相同类型节点的比较
若是两个节点类型相同时,Diff算法会更新节点的属性实现转换。

列表节点的比较
列表节点的操作一般包括添加、删除和排序,列表节点需要我们给它一个key才能进行高效的比较。

Vue Diff算法的实现

了解了Diff算法的大体思路后,来看下Vue中的Diff算法是如何实现的。

Vue的Diff算法与上面的思路大体相似,只比较同级的节点,若找不到与新节点类型相同的节点,则插入一个新节点,若有相同类型的节点则进行节点属性的更新,最后删除新节点列表中不包含的旧节点。具体的实现在vue源码的src/core/vdom/patch.js中的updateChildren方法中,由于代码较长,下面简单说一下整个的比较流程。

初始化
在这里插入图片描述
如上图,有一组新旧节点数组before:[A, B, C, D]、after:[E, C, F, G],我们设置了四个哨兵节点,oldStartIdx、newStartIdx、oldEndIdx、newEndIdx分别指向新旧节点数组的起始下标和开始下标,值为0,0,3,3;oldStartVnode,newStartVnode,oldEndVnode,newEndVnode则分别指向了before和after节点列表中对应哨兵节点下标的值,值为before[oldStartIdx],after[newStartIdx],before[oldEndIdx],after[newEndIdx]。

Diff
当哨兵满足oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx的条件的时候,我们会循环进行一系列节点之间的比较。

优先判断
我们首先对上面声明的各个节点进行一些优先级较高的判断。

判断1:oldStartVnode是否为空,若为true则oldStartIdx向后移动,继续下一个节点的判断。判断代码如下:

if (isUndef(oldStartVnode)) {
   
    // 更新哨兵
    oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
}

判断2:oldEndVnode是否为空,若为true则oldEndIdx向前移动。判断代码如下:

else if (isUndef(oldEndVnode)) {
   
    oldEndVnode = oldCh[--oldEndIdx]
}

判断3:使用 sameVnode判断before和aft

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值