Vue3.0 diff更新过程

641 阅读2分钟

概述

        vue3.0的节点中增加了一个dynamicChildren属性,直接遍历所有的动态子元素,省略了遍历静态元素的时间,如果dynamicChildren没有的时候,直接进行全量的diff运算。

dynamicChildren

       先来看一下dynamicChildren的生成过程。dynamicChildren的生成过程是在vnode生成过程中,如果是组件或者是元素的patchFlag>0(含有动态属性、动态class、动态style、动态文案等)的会加入currentBlock中,通过setupBlock方法将currentBlock放到vnode的dynamicChildren上。

dynamicChildren是在创建vnode的过程中生成。生成过程如下:

更新过程概述

    触发节点更新的时候,如果节点中含有dynamicChildren属性并且patchFlag>0的时候,直接遍历更新dynamicChildren中的节点。这种方式的好处是节省了全部子节点遍历的时间,只遍历动态节点部分,提高了工作效率。如果节点中不包含dynamicChildren的话,则需要进行全量diff。

虚拟dom的diff算法

根据节点是否包含key值,分为两种情况。

  • 没有key的情况下,则取新、老子节点数组的最小长度,将这部分的子节点进行更新。如果老的子节点多的话,则删除多余的节点。否则新增子节点。
  • 有key的情况比较复杂,可以用下图进行说明。

  • 对于如上节点,可以从头开始比较,对于a、b节点是相同的,则继续对a、b节点执行patch方法进行相应的递归更新。
  • 从 c节点开始新旧节点不再相同,则新、旧树的指针继续从尾部开始比较,发现f节点相同,则继续对f节点执行patch方法进行相应的递归更新。     

1. 经过前面两个步骤,假如出现旧节点已经遍历完,而新节点还存在节点的话,如上图所示,新节点还存在节点c,则需要安装c节点。
2. 假如存在新节点已经遍历结束,而老节点还存在节点c,则需要将c节点进行卸载。

3. 假如新、旧子节点队列都有节点没有遍历

(1)  遍历旧节点中没有遍历的部分(e、d、c、 h),寻找和新节点中相同的节点(c、d、 e),如果没有找到,则删除该节点(h);如果找到相同节点则执行patch方法对该节(e,d,c)进行递归更新。

(2) 遍历新节点,如果存在新节点则安装该节点,对于原先存在的节点(e、d、c)则需要从后到前依此移动节点位置改为e,然后d放到e之前,c放到d之前。

综述

        以上主要分析了节点更新过程的逻辑,vue3.0做了很大的优化。在此基础上,可以思考下还有没有可以优化的空间。