
前言:
在上篇文章React源码解析之workLoop
中有提到 React 利用 childExpirationTime,来跳过子树的遍历及渲染,本文讲下 childExpirationTime 的含义和作用。
expirationTime 是如何产生的?
每当节点调用setState
,就会产生一个update
并且计算出一个expirationTime
(关于 expirationTime 的计算,请看:React源码解析之ExpirationTime)
childExpirationTime 是如何产生的?

由于 React 的更新是从FiberRoot
开始的,所以当某一节点发生更新时,React 会向上遍历,直至找到FiberRoot
。
在向上遍历的过程中,会顺便找到发生更新节点的父节点,当找到父节点的时候,由于它们的子节点发生了更新,所以会在父节点上设置childExpirationTime
注意:
(1)多个子节点更新,取最大的expirationTime
作为父节点的childExpirationTime
每个父节点上只会有一个expirationTime
和一个childExpirationTime
,当有多个子节点都有更新时,取子节点最大的(优先级最高的)expirationTime
,作为父节点的childExpirationTime
(2)单个子节点多次更新,取某次更新出的最大的expirationTime
作为自身的expirationTime
childExpirationTime 的作用?
在 React 自上而下更新 fiber 树的时候,每个节点会执行update
方法,根据expirationTime
和childExpirationTime
的优先级大小来判断该节点本身、该节点的子节点是否需要在本次渲染(这一帧)的时候更新。
举个例子:
上图的List
产生的更新的expirationTime
为 250(假设的,实际上是个时间戳),Span1
的expirationTime
为 100,Span2
的expirationTime
为 200,明显 Span2 的优先级高于 Span1,所以List
的childExpirationTime
设为 200
其他节点均无更新,expirationTime=NoWork
即 0,当 React 自上而下遍历到List
节点时,发现它的 fiber 对象的expirationTime
大于childExpirationTime
,所以会优先执行List
自身的更新,如果这一帧留给 React 的时间还够的话,会执行其子节点的更新,否则就跳过,放在下一帧执行
可以想象,如果不设置childExpirationTime
的话,还要继续向下遍历获取子节点的expirationTime
再拿去跟父节点的expirationTime
比较,看谁先更新,是浪费性能的做法。

(完)
网友评论