持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情
Vue2和Vue3和React三者的diff算法有什么区别?
diff 算法是 vue2.x , vue3.x 以及 react 中关键核心点,三者的diff又有什么区别,这个问题是在社区里面讨论很多的话题,面试的时候也经常遇到,本节希望可以用比较通俗易懂的语言解释一下这三者中最大的区别。
diff 算法
其实我们之前也有说过不论 Vue、React数据更新之后,重新生成 VDOM,然后对虚拟DOM进行对比,然后找出需要更新的节点。相信很多人了解 diff 算法也是在这些框架中了解的吧!
但是!但是 diff 算法其实是一个非常普遍常用的方法,例如提交github pr 或者(gitlab mr)时,会对比当前提交代码的改动,这就是 diff 。
Vue、React 的 diff 不是对比文字,而是 vdom 树,即 tree diff 。
传统的 tree diff 算法复杂度是O(n^3),算法不可用。 既然不可用那怎么办呢?那就进行优化!
tree diff优化
传统的 tree diff 算法复杂度是 O(n^3),不可用。
tree diff优化的关键就是只对比同层的节点,而不是跨层对比,这也是考虑到在实际业务中很少会去跨层的移动 DOM 元素。
Vue React 都是用于网页开发,基于 DOM 结构,对 diff 算法都进行了优化(或者简化)
- 只在同一层级比较,不跨层级
- 在网页DOM树中,很少会有跨级别的移动,一般都是同级别的删除、移动。
tag不同则直接删掉重建,不去对比内部细节- 和上一点差不多一个意思,一旦发现不同,不深入进行比较。
- 对DOM类型的元素来说,key 和 tag 都相同才会复用。
- 同一个节点下的子节点,通过
key区分- 这个不论我们在写 Vue 还是 React的循环的时候,都需要有一个key,不然的话就会收到警告或者报错
通过这么三个小点的优化之后,最终把时间复杂度降低到 O(n) ,生产环境下可用。这一点 Vue React 都是相同的。
从左边的树到右边的树,用我们优化之后的diff算法会这么表现?
- 上图实例中
- 灰色表示没有发生变化的节点
- 红色表示被删除的节点
- 绿色表示新增的节点 我们可以发现 root、b并没有被删除,a和c节点同节点比较的时候发现没有,直接进行删除,然后新增a和c节点。
Vue2和Vue3和React三者的diff的特点分别是?
React diff 特点
- 仅向右移动 我们来举一个简单的例子:
源数据: a b c d e
目标数据: b c a d e 目标是:按照React diff 特点(仅向右移动)模拟dom更新的过程
- 首先我们发现目标数据b和源数据的位置不一致
- 正常的话交换位置,我们会将源数据的b左移动和a进行交换位置
- 但是遵循仅向右移动原则,我们不能进行移动,然后往后走
- 我们发现目标数据c和源数据的位置不一致
- 但是遵循仅向右移动原则,我们不能进行移动,继续往后走
- 接着我们到了目标 a 的位置
- 我们发现源数据的a可以遵循仅向右移动原则
- 当a移动到新位置之后,b和c就自然左移,这里就完成了,我们的目标数据的转换了。
Vue2 diff 特点
vue2 的 diff 位于Vue源码的 patch.js 文件中,该算法来源于 snabbdom,复杂度为 O(n)。
- 特点:双端比较
- 同时从新旧 children 的两端开始进行比较,借助 key 可以复用的节点。
- 定义四个指针(oldStartNode, oldEndNode, newStartNode, newEndNode),两两进行比较,之后每移动一次,都会进行一次比较,知道移动到中间的时候相遇了
- oldStartNode 和 newStartNode
- oldStartNode 和 newEndNode
- oldEndNode 和 newStartNode
- oldEndNode 和 newEndNode
Vue3 diff 特点
- 最长递增子序列
- 借鉴了一些别的算法 inferno(github.com/infernojs/i…)
- 处理相同的前置和后置元素的预处理; 2.一旦需要进行 DOM 移动,我们首先要做的就是找到 source 的最长递增子序列。 该方法旨在尽量减少 DOM 的移动,达到最少的 DOM 操作。
Vue和React循环中为什么都需要key?
- vdom diff算法中会根据key判断元素是否要删除
- 匹配了key
- 在vue中:借助 key 可以复用的节点。
- react 通过 key 和 tag 来对节点进行取舍
- 没有匹配key
- 那么可以重复使用的元素则是选择删除重建,过程中需要重新进行渲染,会消耗一部分性能。
总结
- diff 算法
- diff算法很早就有
- diff算法应用很广泛,例如提交github pr 或者(gitlab mr)
- 如果要严格diff两棵树,时间复杂度是
O(n^3),算法不可用。
- tree diff优化
- 之比较同一层级,不跨级比较
- tag 不同则删掉重建(不再去比较内部的细节)
- React diff 特点
- 仅向右移动
- Vue2 diff 特点
- 时从新旧 children 的两端开始进行比较,借助 key 可以复用的节点。
- 定义四个指针(oldStartNode, oldEndNode, newStartNode, newEndNode),两两进行比较,之后每移动一次,都会进行一次比较,知道移动到中间的时候相遇了
- Vue3 diff 特点
- 最长递增子序列
推荐
【1】diff算法深入一下?