移动:组件D已经在集合(A,B,C,D)里了 , 且集合更新时 , D没有发生更新 , 只是位置改变 , 如新集合(A,D,B,C) , D在第二个 , 无须像传统diff , 让旧集合的第二个B和新集合的第二个D 比较 , 并且删除第二个位置的B , 再在第二个位置插入D , 而是 (对同一层级的同组子节点) 添加唯一key进行区分 , 移动即可 。
移动的条件:
- 对新集合中的节点进行循环遍历 , 新旧集合中是否存在相同节点
- nextIndex: 新集合中当前节点的位置
- lastIndex: 访问过的节点在旧集合中最右的位置(最大位置)
- If (child._mountIndex < lastIndex)
文章插图
(1)看着上图的 B , React先从新中取得B , 然后判断旧中是否存在相同节点B , 当发现存在节点B后 , 就去判断是否移动B 。
B在旧 中的index=1 , 它的lastIndex=0 , 不满足 index < lastIndex 的条件 , 因此 B 不做移动操作 。此时 , 一个操作是 , lastIndex=(index,lastIndex)中的较大数=1.
注意:lastIndex有点像浮标 , 或者说是一个map的索引 , 一开始默认值是0 , 它会与map中的元素进行比较 , 比较完后 , 会改变自己的值的(取index和lastIndex的较大数) 。
(2)看着 A , A在旧的index=0 , 此时的lastIndex=1(因为先前与新的B比较过了) , 满足index<lastIndex , 因此 , 对A进行移动操作 , 此时 lastIndex=max(index,lastIndex)=1 。
(3)看着D , 同(1) , 不移动 , 由于D在旧的index=3 , 比较时 , lastIndex=1 , 所以改变lastIndex=max(index,lastIndex)=3
(4)看着C , 同(2) , 移动 , C在旧的index=2 , 满足index<lastIndex(lastIndex=3) , 所以移动 。
由于C已经是最后一个节点 , 所以diff操作结束 。
情形二:新集合中有新加入的节点 , 旧集合中有删除的节点
文章插图
(1)B不移动 , 不赘述 , 更新l astIndex=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 , 此时D不移动 , 但它的index是最大的 , 导致更新lastIndex=3 , 从而使得其他元素A,B,C的index<lastIndex , 导致A,B,C都要去移动 。
理想情况是只移动D , 不移动A,B,C 。因此 , 在开发过程中 , 尽量减少类似将最后一个节点移动到列表首部的操作 , 当节点数量过大或更新操作过于频繁时 , 会影响React的渲染性能 。
【diff算法介绍】
推荐阅读
- 中国婚庆协会介绍
- 中国婚庆网详细介绍
- 酸奶机做米酒方法介绍
- 排风扇规格介绍
- 米砖茶功效与作用,花砖茶的功效与作用介绍
- 介绍普洱茶喝法,生普洱茶喝法
- 世界最大的邮轮是多少吨 海洋绿洲号游轮介绍
- 介绍三角鱼的样子 像三角形的鱼
- Python算法中的时间复杂度
- Linux一键配置工具ezhttp介绍