前言:
在上篇文章React源码解析之workLoop
中有提到 React 利用 childExpirationTime,来跳过子树的遍历及渲染,本文讲下 childExpirationTime 的含义和做用。app
expirationTime 是如何产生的?
每当节点调用setState
,就会产生一个update
而且计算出一个expirationTime
(关于 expirationTime 的计算,请看:React源码解析之ExpirationTime)oop
childExpirationTime 是如何产生的?post
因为 React 的更新是从FiberRoot
开始的,因此当某一节点发生更新时,React 会向上遍历,直至找到FiberRoot
。性能
在向上遍历的过程当中,会顺便找到发生更新节点的父节点,当找到父节点的时候,因为它们的子节点发生了更新,因此会在父节点上设置childExpirationTime
3d
注意:
(1)多个子节点更新,取最大的expirationTime
做为父节点的childExpirationTime
每一个父节点上只会有一个expirationTime
和一个childExpirationTime
,当有多个子节点都有更新时,取子节点最大的(优先级最高的)expirationTime
,做为父节点的childExpirationTime
code
(2)单个子节点屡次更新,取某次更新出的最大的expirationTime
做为自身的expirationTime
cdn
childExpirationTime 的做用?
在 React 自上而下更新 fiber 树的时候,每一个节点会执行update
方法,根据expirationTime
和childExpirationTime
的优先级大小来判断该节点自己、该节点的子节点是否须要在本次渲染(这一帧)的时候更新。对象
举个例子:
上图的List
产生的更新的expirationTime
为 250(假设的,其实是个时间戳),Span1
的expirationTime
为 100,Span2
的expirationTime
为 200,明显 Span2 的优先级高于 Span1,因此List
的childExpirationTime
设为 200blog
其余节点均无更新,expirationTime=NoWork
即 0,当 React 自上而下遍历到List
节点时,发现它的 fiber 对象的expirationTime
大于childExpirationTime
,因此会优先执行List
自身的更新,若是这一帧留给 React 的时间还够的话,会执行其子节点的更新,不然就跳过,放在下一帧执行rem
能够想象,若是不设置childExpirationTime
的话,还要继续向下遍历获取子节点的expirationTime
再拿去跟父节点的expirationTime
比较,看谁先更新,是浪费性能的作法。
(完)