这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
diff 简介
做 Diff 的目的就是为了复用节点。
React 现在将整体的数据结构从树改为了链表结构。所以相应的 Diff 算法也得改变,以为以前的 Diff 算法就是基于树的。
React16 的 diff 策略采用从链表头部开始比较的算法,是层次遍历,算法是建立在一个节点的插入、删除、移动等操作都是在节点树的同一层级中进行的。
Diff的瓶颈以及React如何应对
由于Diff操作本身也会带来性能损耗,React文档中提到,即使在最前沿的算法中,将前后两棵树完全比对的算法的复杂程度为 O(n 3 ),其中n是树中元素的数量。
如果在React中使用了该算法,那么展示1000个元素所需要执行的计算量将在十亿的量级范围。这个开销实在是太过高昂。
为了降低算法复杂度,React的diff会预设三个限制:
- 只对同级元素进行
Diff。如果一个DOM节点在前后两次更新中跨越了层级,那么React不会尝试复用他。 - 两个不同类型的元素会产生出不同的树。如果元素由
div变为p,React会销毁div及其子孙节点,并新建p及其子孙节点。 - 开发者可以通过
key prop来暗示哪些子元素在不同的渲染下能保持稳定。
// 更新前
<div>
<p key="ka">ka</p>
<h3 key="song">song</h3>
</div>
// 更新后
<div>
<h3 key="song">song</h3>
<p key="ka">ka</p>
</div>
如果没有key,React会认为div的第一个子节点由p变为h3,第二个子节点由h3变为p。这符合限制2的设定,会销毁并新建。
但是当我们用key指明了节点前后对应关系后,React知道key === "ka"的p在更新后还存在,所以DOM节点可以复用,只是需要交换下顺序。
这就是React为了应对算法性能瓶颈做出的三条限制。