1 )概述
completeUnitOfWork
当中,有一步比较重要的一个操作,就是重置 childExpirationTime
childExpirationTime
对于有分叉的点来说是非常重要的, 它可以记录不同的子树所创建的不同的更新completeUnitOfWork
之后,要去更新它的 childExpirationTime
completeUnitOfWork
的时候,也都要去做相同的操作2 )源码
定位到 packages/react-reconciler/src/ReactFiberScheduler.js#L989
对应到代码里面,来看在 completeUnitOfWork
里面,我们这边执行完了 completeWork
马上会执行 resetChildExpirationTime
那么这个方法它具体做了什么呢?
function resetChildExpirationTime(
workInProgress: Fiber,
renderTime: ExpirationTime,
) {
// 首先判断 renderTime ,就是当前正在执行更新的那一个优先级对应的 expirationTime
// 如果它不等于never,并且 workInProgress.childExpirationTime 等于 Never
// 也就是说 workInProgress 就是我们当前节点的子节点优先级最高的那个任务是never
// 就是永远不会更新到的并且我们现在也不是正在执行,never,就是永远不会更新到的那些节点的更新
// 说明我们这边根本就不需要做任何的操作,所以我们直接return就可以了
if (renderTime !== Never && workInProgress.childExpirationTime === Never) {
// The children of this component are hidden. Don't bubble their
// expiration times.
return;
}
let newChildExpirationTime = NoWork;
// Bubble up the earliest expiration time.
// 跳过这个if, 直接到 else
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
// We're in profiling mode.
// Let's use this same traversal to update the render durations.
let actualDuration = workInProgress.actualDuration;
let treeBaseDuration = workInProgress.selfBaseDuration;
// When a fiber is cloned, its actualDuration is reset to 0.
// This value will only be updated if work is done on the fiber (i.e. it doesn't bailout).
// When work is done, it should bubble to the parent's actualDuration.
// If the fiber has not been cloned though, (meaning no work was done),
// Then this value will reflect the amount of time spent working on a previous render.
// In that case it should not bubble.
// We determine whether it was cloned by comparing the child pointer.
const shouldBubbleActualDurations =
workInProgress.alternate === null ||
workInProgress.child !== workInProgress.alternate.child;
let child = workInProgress.child;
while (child !== null) {
const childUpdateExpirationTime = child.expirationTime;
const childChildExpirationTime = child.childExpirationTime;
if (childUpdateExpirationTime > newChildExpirationTime) {
newChildExpirationTime = childUpdateExpirationTime;
}
if (childChildExpirationTime > newChildExpirationTime) {
newChildExpirationTime = childChildExpirationTime;
}
if (shouldBubbleActualDurations) {
actualDuration += child.actualDuration;
}
treeBaseDuration += child.treeBaseDuration;
child = child.sibling;
}
workInProgress.actualDuration = actualDuration;
workInProgress.treeBaseDuration = treeBaseDuration;
} else {
// 这边主要是有一个 while循环, 这个while循环它首先使用的是 workInProgress.child
// 它就是我们当前节点的child,然后获取child的 expirationTime 以及 childChildExpirationTime
// child.expirationTime 是它自身它所创建的更新对应的 expirationTime
// 而 child.childExpirationTime 是child的子树里面任何几个节点它所创建的更新所对应的优先级最高的 expirationTime
let child = workInProgress.child;
while (child !== null) {
// 为什么这边要用这两个值?因为我们没有办法直接拿到当前节点它所有子树最高优先级的点
// 只能是通过去遍历它的所有的第一层的子节点以及每个子节点它的 childExpirationTime
// 因为我们这个 completeUnitOfWork 是由底往上去更新的一个过程
// 那么由底往上更新的过程,就会每一个节点都会对应这个操作
// 对应的这个操作之后,它肯定就是每一个节点都会更新到优先级最高的那个 expirationTime
const childUpdateExpirationTime = child.expirationTime;
const childChildExpirationTime = child.childExpirationTime;
// 接下来进行判断更新
if (childUpdateExpirationTime > newChildExpirationTime) {
newChildExpirationTime = childUpdateExpirationTime;
}
if (childChildExpirationTime > newChildExpirationTime) {
newChildExpirationTime = childChildExpirationTime;
}
// 下一个节点
child = child.sibling;
}
}
workInProgress.childExpirationTime = newChildExpirationTime;
}