React之diff算法

diff算法的作用

计算出Virtual DOM(虚拟DOM)中真正变化的部分,并只针对该部分进行原生DOM操作,而非重新渲染整个页面。

传统diff算法与React diff算法

传统diff算法

传统diff算法是通过循环递归对节点进行依次对比,算法事件复杂度达到O(n3),n是树的节点树。试想,如果要展示1000个节点,那么就需要执行上亿次比较,CPU的压力是非常大的。

React的diff算法

首先来看一个概念:

调和:将Virtual DOM(虚拟DOM)树转换成Actual DOM(真实DOM)树最少操作过程称为调和。

React diff算法:是调和的具体实现。

diff 策略

React使用三大策略,将O(n3)复杂度转换成O(n)复杂度

策略一(tree diff): Web UI中DOM节点跨层级的移动操作特别少,可以忽略不计;

策略二(component diff):拥有相同类的两个组件生成相似的树形结构;拥有不同类的两个组件,生成不同的树形结构;

策略三(elememt diff):对同一层级的一组子节点,通过唯一id进行区分。

tree diff

(1)React通过updateDepth对Vertual DOM进行层级控制
(2)对树分层比较,两棵树只对同一层节点进行比较。如果该节点不存在,则该节点及其子节点会被完全删除,不会再进一步比较。
(3)只需遍历一次,就能完成整颗DOM树的比较
在这里插入图片描述

component diff

即React对不同组件间的比较,有三种策略

(1)同一类型的两个组件,按原策略(层级比较)继续比较Virtual DOM树即可
(2)同一类型的两个组件,组件A变化为组件B时,可能Virtual DOM没有任何变化,用户如果知道这一点,可以节省大量计算时间,所以用户可以通过shouldComponentUpdate()来判断是否需要计算
(3)不同类型的组件,将一个(将被改变的)组件判断为dirtycomponent(脏组件),从而替换整个组件的所有节点

注意:如果组件D和组件G的结构相似,但是React判断是不同类型的组件,则不会比较其结构,而是删除组件D及其子节点,创建组件G及其子节点。

elememt diff

当节点处于同一层级时,diff提供三种节点操作:删除、插入、移动。

(1)插入:组件C不在集合(A,B)中,需要插入

(2)删除

  • 组件D在集合(A,B,D)中,但D的节点已经更改,不能复用和更新,所以需要删除旧的D,再创建新的。
  • 组件D之前在集合(A,B,D)中,但集合变成新的集合(A,B)了,D就需要被删除。

(3)移动:组件D已经在集合(A,B,C,D)里了,且集合更新时,D没有发生更新,只是位置改变,如集合(A,D,B,C),D在第二个,无须像传统diff,让旧集合的第二个B和新集合的第二个D比较,并且删除第二个位置的B,再在第二个位置插入D,而是(对同一层级的同组子节点)添加唯一key进行区分,移动即可。

第一种移动:新旧集合中存在相同节点但位置不同时,如何移动节点
在这里插入图片描述
新的节点集合里面的B:React先从新中取得B,然后判断旧中是否存在相同节点B,当发现存在节点B后,就去判断是否移动B。

判断是否移动:

(1)对于B:旧的集合中的index=1,它的lastIndex=0,不满足index<lastIndex的条件,因此B不做移动操作。

此时,lastIndex=(index,lastIndex)中较大的数=1

(2)再看A:旧的集合里面index=0,此时的lastIndex=1,满足index<lastIndex,因此对A进行移动操作。

此时,lastIndex=(index,lastIndex)中较大的数=1

(3)再看D:旧的集合中index=3,此时lastIndex=1,不满足条件,因此D不移动。

此时,lastIndex=(index,lastIndex)中较大的数=3

(4)再看C:旧的集合里面index=2,此时的lastIndex=3,满足index<lastIndex,因此对C进行移动操作。

由于C是最后一个节点,所以diff操作结束。

第二种移动:新集合中有新加入的节点,旧集合中有删除的节点
在这里插入图片描述
(1)同上面的情况,B不移动,更新lastIndex=1;

(2)(增加节点)新集合取得E,发现旧集合中不存在,故在lastIndex=1的位置创建E,更新lastIndex=1;

(3)新集合取得C,C不移动,更新lastIndex=2;

(4)新集合取得A,A移动,更新lastIndex=2;

(5)(删除节点)新集合对比后,再对旧集合遍历。判断新集合没有,但旧集合有的元素(如D),发现D,删除D,diff操作结束。

diff 的不足与待优化

在这里插入图片描述
如图所示,节点D在旧的集合中的index=3,此时lastIndex=0,不满足index<lastIndex的条件,因此D不做移动操作。但是它的index是最大的,导致此时的lastIndex更新为3,从而使其他元素A,B,C都满足index<lastIndex,导致A,B,C都要移动。

理想情况下是只移动D,不移动A,B,C。因此,在开发过程中,尽量减少类似将最后一个节点移动到列表首部的操作(图中的D从最后一个变到第一个),当节点数量过大或更新操作过于频繁时,会影响React的渲染性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值