React和Vue的Diff区别

349 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

复杂度

传统diff算法复杂度为O(n^3), vue2.x加入了 Virtual Dom和react拥有相同的diff优化原则(将算法复杂度降为O(n))

两者流程思路类似

-   只在同一层级比较,不跨层级

-   不同的组件产生不同的 DOM 结构。当type不相同时,对应DOM操作就是直接销毁老的DOM,创建新的DOM,不需要再对比内部细节。

-   同一个节点下的子节点,通过 `key` 区分

image.png

源码则不同

React

image.png

react首先对新集合进行遍历,for( name in nextChildren)。

通过唯一key来判断老集合中是否存在相同的节点。如果没有的话创建

如果有的话,if (preChild === nextChild )

  • 会将节点在新集合中的位置和在老集合中lastIndex进行比较
    
  • 如果if (child._mountIndex < lastIndex) 进行移动操作,否则不进行移动操作。
    
  • 如果遍历的过程中,发现在新集合中没有,但在老集合中有的节点,会进行删除操作
    

简单示例:

image.png

  • 首先我们发现目标数据b和源数据的位置不一致

    • 正常的话交换位置,我们会将源数据的b左移动和a进行交换位置
    • 但是遵循仅向右移动原则,我们不能进行移动,然后往后走
  • 我们发现目标数据c和源数据的位置不一致

    • 但是遵循仅向右移动原则,我们不能进行移动,继续往后走
  • 接着我们到了目标 a 的位置

    • 我们发现源数据的a可以遵循仅向右移动原则
  • 当a移动到新位置之后,b和c就自然左移,这里就完成了,我们的目标数据的转换了。

Vue2

updateChildren是vue diff的核心, 过程可以概括为:

旧children和新children各有两个头尾的变量StartIdx和EndIdx,它们的2个变量相互比较,一共有4种比较方式。

如果4种比较都没匹配,如果设置了key,就会用key进行比较,在比较的过程中,变量会往中间靠,一旦StartIdx>EndIdx表明旧children和新children至少有一个已经遍历完了,就会结束比较。

image.png

Vue2的核心Diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。相比React的Diff算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。

Vue3

基于Vue2的基础上添加最长递增子序列inferno(github.com/infernojs/i…)

注:

1.处理相同的前置和后置元素的预处理

2.一旦需要进行 DOM 移动,我们首先要做的就是找到 source 的最长递增子序列。 该方法旨在尽量减少 DOM 的移动,达到最少的 DOM 操作

拓展小知识

Vue和React为什么都需要key

  • vdom diff算法中会根据key判断元素是否要删除

  • 匹配了key

    • 在vue中:借助 key 可以复用的节点。

    • react 通过 key 和 tag 来对节点进行取舍

  • 没有匹配key

    • 那么可以重复使用的元素则是选择删除重建,过程中需要重新进行渲染,会消耗一部分性能。

本文参考

Vue Diff <|>React Diff <|>前端风神 <|>是洋柿子啊 <|>Vue和React的区别