Vue diff和React diff

693 阅读2分钟

React中的算法和数据结构

深度优先搜索、递归、动态规划、散列表、数组、链表、二叉树、、栈

Vue中的算法和数据结构

动态规划、递归、二分查找、散列表、LRU(最近最少使用)、数组

Vue diff

mini-vue-diff

vue diff.jpg

数据结构
  • 两个vdom数组
条件
  • 两个指针,一个指向第一位、一个指向最后一位
  • 存在两个vdom数组,一个是老的vdom,一个是新的vdom
流程
  • 从前往后找,比较两个节点,如果节点不能复用,停止
  • 从后往前找,比较两个节点,如果节点不能复用,则停止
  • 如果老节点没有了,剩余的新节点都是新增的
  • 如果新节点没有了,剩余的老节点都是需要删除的
  • 如果新老节点都有
  1. 为了方便接下来的查找,把新节点做成key:index的Map图
  2. 遍历老节点数组(剩余部分),根据key属性在Map中查找,如果能找到,表示这个节点是可以被复用的。

React diff

reconcileChildrenArray

比较的是key和tag

react diff.jpg

数据结构
  • 新vdom是数组,也就是newChildren,老vdom是fiber单链表,也就是oldFiber
条件
  • 一个指针
  • 新旧两个单向Fiber链表(初次渲染阶段没有老链表)
流程
  • 新老VDOM都是从左边开始遍历的,按位置比较,即第i个老vdom和第i个新vdom比较,如果节点可以复用,那么先复用,然后新老vdom都往后移一位,否则就中止本轮循环。
  • 如果经过step1,新节点已经遍历完了,那么如果还有剩下的老节点,删除即可。
  • 如果经过step1,老节点没了,新节点还有,那么新节点逐个新增即可。初次渲染走的就是这里。
  • 走到现在,新老节点都还有,但是是乱序的。因此可以把oldFiber单链表做成Map(key:Fiber),即existingChildren,接下来遍历newChildren,找到能复用的fiber,就复用并且从existingChildren删除这个fiber。
  • 经历过step4之后,发现老节点existingChildren中还有没被复用的,全部删除即可

区别

数据结构不同
  • vue:数组
  • React:Fiber的单链表,所以无法反向遍历,如果设计成双链表,但是空间上会多一倍
比较过程不同
  • vue:是从前往后,然后重后往前
  • React:只有从前往后的过程
临时存储Map不同
  • vue:使用map进行存储是 key:index,存储的是节点数组
  • React:map存储是 key:Fiber,存储的是链表