vue3和react虚拟DOM的diff算法区别

vue3

随着Vue3.0版本的发布,我们在使用或者对其源码进行阅读时会惊讶的发现,它又又又双叒叕变强了,尤大本人在直播中也提到新的Vue会比老的Vue有1.3到2倍的提升,它的更新机制会更加的快速敏捷。下面就抛砖引玉,给大家稍微介绍下在更新机制方面主要升级的两个点:

节点移动优化

要从一道算法题说起:

在一个给定的数组中,找到一组递增的数值,并且长度尽可能的大。

有点比较难理解,那来看具体例子:

const arr = [10,9,2,5,3,7,101,18]

[2, 3, 7, 18]这一列数组就是arr的最长递增子序列,其实[2, 3, 7, 101]也是。 所以最长递增子序列符合三个要求:

  1. 子序列内的数值是递增的
  2. 子序列内数值的下标在原数组中是递增的
  3. 这个子序列是能够找到的最长的

但是我们一般会找到数值较小的那一组数列,因为他们可以增长的空间会更多。

想必读完题目,大家就会发现:”这不就是求解最长递增子序列嘛?力扣都刷吐了的题了,小菜一碟。“如果是这样的话,那这个节点移动优化也就不难理解了。是的,Vue3.0就运用了求解这个问题的基础算法来实现diff过程中的更新优化,目的就是找到顺序排列的不需要变动的节点,使更新操作变得更少,如下图的LBN三个节点。

patchFlags

首先解释下什么是patchFlags, patchFlag 是 complier 时的 transform 阶段解析 AST Element 打上的优化标识。并且,顾名思义 patchFlag,patch 一词表示着它会为 runtime 时的 patchVNode 提供依据,从而实现靶向更新 VNode 的效果。因此,这样一来一往,也就是耳熟能详的 Vue3 巧妙结合 runtime 与 compiler 实现靶向更新和静态提升。代码里,patchFlag 被定义为一个数字枚举类型,每一个枚举值对应的标识意义会是这样:

export const enum PatchFlags {
  
  TEXT = 1,// 动态的文本节点
  CLASS = 1 << 1,  // 2 动态的 class
  STYLE = 1 << 2,  // 4 动态的 style
  PROPS = 1 << 3,  // 8 动态属性,不包括类名和样式
  FULL_PROPS = 1 << 4,  // 16 动态 key,当 key 变化时需要完整的 diff 算法做比较
  HYDRATE_EVENTS = 1 << 5,  // 32 表示带有事件监听器的节点
  STABLE_FRAGMENT = 1 << 6,   // 64 一个不会改变子节点顺序的 Fragment
  KEYED_FRAGMENT = 1 << 7, // 128 带有 key 属性的 Fragment
  UNKEYED_FRAGMENT = 1 << 8, // 256 子节点没有 key 的 Fragment
  NEED_PATCH = 1 << 9,   // 512
  DYNAMIC_SLOTS = 1 << 10,  // 动态 solt
  HOISTED = -1,  // 特殊标志是负整数表示永远不会用作 diff
  BAIL = -2 // 一个特殊的标志,指代差异算法
}

这样定义有一个好处,就是一个节点可能是多个类型,那么只需要将多个类型的值做一次按位或就可以了。

例如:一个节点既是文本节点,又带有事件监听器

那么这个节点最终的属性值则为:

      文本节点       0000 0001
      
                      按位或
                      
      事件监听       0001 0000
      
      最终的值       0001 0001

十进制表示为33,有了这个值我们就可以在更新节点时进行相应的处理了。 在判断该节点是否是这个类型时,只需要将该节点的值33和这个类型的值做一次与运算之后看看是否跟这个值相同即可。

例如:

  1. 证明33这个节点是否是文本节点?(33 & 1) === 1 为true,则是文本节点
  2. 证明33这个节点是否为事件监听?(33 & 32) === 32 为true,则为事件监听节点
  3. 证明33这个节点不是动态的style节点?(33 & 4) === 4 为false,则不是动态style节点

 

 

其中大致可以分为两类:

  • 当 patchFlag 的值「大于」 0 时,代表所对应的元素在 patchVNode 时或 render 时是可以被优化生成或更新的。

  • 当 patchFlag 的值「小于」 0 时,代表所对应的元素在 patchVNode 时,是需要被 full diff,即进行递归遍历 VNode tree 的比较更新过程。

总结:「Vue3.0对于不参与更新的元素,做静态标记并提示,只会被创建一次,在渲染时直接复用。」

react

vue和react的diff算法,都是忽略跨级比较,只做同级比较。vue diff时调动patch函数,参数是vnode和oldVnode,分别代表新旧节点。

1.vue对比节点。当节点元素相同,但是classname不同,认为是不同类型的元素,删除重建,而react认为是同类型节点,只是修改节点属性。

2.vue的列表对比,采用的是两端到中间比对的方式,而react采用的是从左到右依次对比的方式。当一个集合只是把最后一个节点移到了第一个,react会把前面的节点依次移动,而vue只会把最后一个节点移到第一个。总体上,vue的方式比较高效。

转自:https://www.ngui.cc/article/show-166792.html?action=onClick

posted @ 2022-09-25 01:51  蓓蕾心晴  阅读(499)  评论(0编辑  收藏  举报