dom-diff
Diff的瓶颈以及React如何应对
由于 Diff 操作本身也会带来性能损耗,React文档中提到,即使在最前沿的算法中,将前后两棵树完全比对的算法的复杂程度为 O(n 3 ),其中 n 是树中元素的数量。
如果在 React 中使用了该算法,那么展示 1000个元素所需要执行的计算量将在十亿的量级范围。这个开销实在是太过高昂。
为了降低算法复杂度,React的diff会预设三个限制:
只对同级元素进行Diff。如果一个DOM节点在前后两次更新中跨越了层级,那么React不会尝试复用他。
两个不同类型的元素会产生出不同的树。如果元素由
div
变为p
,React会销毁div
及其子孙节点,并新建p
及其子孙节点。开发者可以通过
key
属性 来暗示哪些子元素在不同的渲染下能保持稳定。考虑如下例子:
// 更新前
<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为了应对算法性能瓶颈做出的三条限制。
Diff是如何实现的
在函数内部,会根据newChild
类型调用不同的处理函数。
这里的newChild
参数就是本次更新的 JSX 对象(对应ClassComponent
的this.render
方法返回值,或者FunctionComponent
执行的返回值)
不同类型的Diff是如何实现的
我们可以从同级的节点数量将Diff分为两类:
当
newChild
类型为object
、number
、string
,代表同级只有一个节点当
newChild
类型为Array
,同级有多个节点
接下来,我们分别讨论。
情况一:同级只有一个节点的Diff
对于单个节点,我们以类型object
为例,会进入reconcileSingleElement
Last updated