React16源码: React中的completeUnitOfWork的源码实现

时间:2024-01-23 22:54:48
// 这个API 是在 workInProgress 的基础上进行的一个操作 function completeUnitOfWork(workInProgress: Fiber): Fiber | null { // Attempt to complete the current unit of work, then move to the // next sibling. If there are no more siblings, return to the // parent fiber. // 进来首先就是一个 while true 的一个循环 while (true) { // The current, flushed, state of this fiber is the alternate. // Ideally nothing should rely on this, but relying on it here // means that we don't need an additional field on the work in // progress. // 对于这个循环, 它首先获取current const current = workInProgress.alternate; if (__DEV__) { ReactCurrentFiber.setCurrentFiber(workInProgress); } // 然后 获取 returnFiber 和 siblingFiber,也就是它的父节点以及它的兄弟节点 // 这个在后面我们判断是否要返回兄弟节点的时候就会用到 const returnFiber = workInProgress.return; const siblingFiber = workInProgress.sibling; // 这里首先一进来就有一个大的判断,它是一个整个方法里面最大的一个判断 // Incomplete 就是这个节点它是出现了错误,然后被捕获的, 并标记这个 sideEffect // 逻辑与操作来判断某一个属性上面它是否有某一个特性的一个方式 if ((workInProgress.effectTag & Incomplete) === NoEffect) { if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) { // Don't replay if it fails during completion phase. mayReplayFailedUnitOfWork = false; } // This fiber completed. // Remember we're completing this unit so we can find a boundary if it fails. nextUnitOfWork = workInProgress; if (enableProfilerTimer) { if (workInProgress.mode & ProfileMode) { startProfilerTimer(workInProgress); } nextUnitOfWork = completeWork( current, workInProgress, nextRenderExpirationTime, ); if (workInProgress.mode & ProfileMode) { // Update render duration assuming we didn't error. stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); } } else { nextUnitOfWork = completeWork( current, workInProgress, nextRenderExpirationTime, ); } if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) { // We're out of completion phase so replaying is fine now. mayReplayFailedUnitOfWork = true; } stopWorkTimer(workInProgress); resetChildExpirationTime(workInProgress, nextRenderExpirationTime); if (__DEV__) { ReactCurrentFiber.resetCurrentFiber(); } if (nextUnitOfWork !== null) { // Completing this fiber spawned new work. Work on that next. return nextUnitOfWork; } // 接下去这个个判断,是要构造一个所有 有 SideEffect 的节点的一个链状的结构 // 这个链状结构最终是用于 commitWork 的时候用来进行对这些有 SideEffect的节点进行 commit 的一个操作, // 这边它的一个判断条件,returnFiber不等于null,并且returnFiber它不是一个 Incomplete 的一个节点 // 因为对于一个 Incomplete 的节点,它唯一可以具有的一个SideEffect,就是这个节点已经被捕获了 // 因为对于有 Incomplete 错误的节点是不会渲染正常的子节点的 if ( returnFiber !== null && // Do not append effects to parents if a sibling failed to complete (returnFiber.effectTag & Incomplete) === NoEffect ) { // Append all the effects of the subtree and this fiber onto the effect // list of the parent. The completion order of the children affects the // side-effect order. // 对于正常的一个情况, 首先要判断一下 returnFiber.firstEffect 是否等于 null // 符合判断就代表 现在这个 returnFiber 上还没有记录任何它的子节点的有副作用的子节点 // 这个时候, 直接把当前节点的firstEffect赋值给 returnFiber.firstEffect // 因为它之前是没有任何一个的嘛,我们这边真正要做的是把当前节点的 firstEffect 到 lastEffect的一个链条 // 这个单项链表,给它挂载到它的父节点的同样的一个 firstEffect到lastEffect的单项链表的最后 if (returnFiber.firstEffect === null) { returnFiber.firstEffect = workInProgress.firstEffect; } // 就是下面这一段判断,就是来做这个事情的, 如果returnFiber.lastEffect不等于null,那说明它已经有了 // 那么对于returnFiber上面有记录过别的 SideEffect 的节点之后 // 我们当前节点是挂载到整个 SideEffect 链的最后,就是下面这样,就是把它连到最后的上面 if (workInProgress.lastEffect !== null) { if (returnFiber.lastEffect !== null) { returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; } // 还要操作如下,因为它的这个(returnFiber.lastEffect)指针目前还指向它原来的那个lastEffect // 在 赋值 nextEffect之后,它的最后一个就是这个链的最后一个已经变成 workInProgress.lastEffect,所以这边要执行这么一个操作 // 当然这个条件是要建立在 workInProgress.lastEffect 是有值的情况 // 这是把它们各自的firsteffect到lasteffect,这个链给它进行一个串联的过程 returnFiber.lastEffect = workInProgress.lastEffect; } // If this fiber had side-effects, we append it AFTER the children's // side-effects. We can perform certain side-effects earlier if // needed, by doing multiple passes over the effect list. We don't want // to schedule our own side-effect on our own list because if end up // reusing children we'll schedule this effect onto itself since we're // at the end. // 对于returnFiber来说,当前这个节点也可能是有副作用的,那么这边就接下去就会做这个操作 // 如果当前节点的 effectTag > PerformedWork 的,因为 PerformedWork 是一个给 DEVTool 用的一个 sideEffect // 对于真正的react更新是没有任何意义的, 所以如果它仅仅只有 PerformedWork ,它就不是一个有效的 SideEffect 的节点 const effectTag = workInProgress.effectTag; // Skip both NoWork and PerformedWork tags when creating the effect list. // PerformedWork effect is read by React DevTools but shouldn't be committed. if (effectTag > PerformedWork) { // 如果它有 SideEffect,就把当前节点作为父节点的 SideEffect 链的最后一个给它挂载上去 // 或者如果是当前父节点没有任何记录的 SideEffect,它就是第一个 if (returnFiber.lastEffect !== null) { returnFiber.lastEffect.nextEffect = workInProgress; } else { returnFiber.firstEffect = workInProgress; } returnFiber.lastEffect = workInProgress; } } if (__DEV__ && ReactFiberInstrumentation.debugTool) { ReactFiberInstrumentation.debugTool.onCompleteWork(workInProgress); } if (siblingFiber !== null) { // If there is more work to do in this returnFiber, do that next. return siblingFiber; } else if (returnFiber !== null) { // If there's no more work in this returnFiber. Complete the returnFiber. workInProgress = returnFiber; continue; } else { // We've reached the root. return null; } } else { if (enableProfilerTimer && workInProgress.mode & ProfileMode) { // Record the render duration for the fiber that errored. stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); // Include the time spent working on failed children before continuing. let actualDuration = workInProgress.actualDuration; let child = workInProgress.child; while (child !== null) { actualDuration += child.actualDuration; child = child.sibling; } workInProgress.actualDuration = actualDuration; } // This fiber did not complete because something threw. Pop values off // the stack without entering the complete phase. If this is a boundary, // capture values if possible. const next = unwindWork(workInProgress, nextRenderExpirationTime); // Because this fiber did not complete, don't reset its expiration time. if (workInProgress.effectTag & DidCapture) { // Restarting an error boundary stopFailedWorkTimer(workInProgress); } else { stopWorkTimer(workInProgress); } if (__DEV__) { ReactCurrentFiber.resetCurrentFiber(); } if (next !== null) { stopWorkTimer(workInProgress); if (__DEV__ && ReactFiberInstrumentation.debugTool) { ReactFiberInstrumentation.debugTool.onCompleteWork(workInProgress); } // If completing this work spawned new work, do that next. We'll come // back here again. // Since we're restarting, remove anything that is not a host effect // from the effect tag. next.effectTag &= HostEffectMask; return next; } if (returnFiber !== null) { // Mark the parent fiber as incomplete and clear its effect list. returnFiber.firstEffect = returnFiber.lastEffect = null; returnFiber.effectTag |= Incomplete; } if (__DEV__ && ReactFiberInstrumentation.debugTool) { ReactFiberInstrumentation.debugTool.onCompleteWork(workInProgress); } // 存在 sibling 节点, 注意这边是return,也就是跳出while循环 if (siblingFiber !== null) { // If there is more work to do in this returnFiber, do that next. return siblingFiber; } else if (returnFiber !== null) { // If there's no more work in this returnFiber. Complete the returnFiber. // 如果returnFiber不等于null,那么 workInProgress = returnFiber // 比如对于最上面示例图的 input节点,它的 completeUnitOfWork // 如果它没有兄弟节点,那么它就继续执行Input的 completeUnitOfWork // 这个循环是在 completeUnitOfWork 内部进行的一个过程 workInProgress = returnFiber; continue; } else { // 如果 returnFiber 也等于null,那么它直接 return null // 说明已经到达顶点了,就到达 RootFiber 了,我们的更新过程呢已经完成了 // 只需要在接下去 commitRoot 就可以了 return null; } } } // Without this explicit null return Flow complains of invalid return type // TODO Remove the above while(true) loop // eslint-disable-next-line no-unreachable return null; }