(unitOfWork: Fiber, skipSiblings: boolean)
| 3336 | } |
| 3337 | |
| 3338 | function unwindUnitOfWork(unitOfWork: Fiber, skipSiblings: boolean): void { |
| 3339 | let incompleteWork: Fiber = unitOfWork; |
| 3340 | do { |
| 3341 | // The current, flushed, state of this fiber is the alternate. Ideally |
| 3342 | // nothing should rely on this, but relying on it here means that we don't |
| 3343 | // need an additional field on the work in progress. |
| 3344 | const current = incompleteWork.alternate; |
| 3345 | |
| 3346 | // This fiber did not complete because something threw. Pop values off |
| 3347 | // the stack without entering the complete phase. If this is a boundary, |
| 3348 | // capture values if possible. |
| 3349 | const next = unwindWork(current, incompleteWork, entangledRenderLanes); |
| 3350 | |
| 3351 | // Because this fiber did not complete, don't reset its lanes. |
| 3352 | |
| 3353 | if (next !== null) { |
| 3354 | // Found a boundary that can handle this exception. Re-renter the |
| 3355 | // begin phase. This branch will return us to the normal work loop. |
| 3356 | // |
| 3357 | // Since we're restarting, remove anything that is not a host effect |
| 3358 | // from the effect tag. |
| 3359 | next.flags &= HostEffectMask; |
| 3360 | workInProgress = next; |
| 3361 | return; |
| 3362 | } |
| 3363 | |
| 3364 | // Keep unwinding until we reach either a boundary or the root. |
| 3365 | |
| 3366 | if (enableProfilerTimer && (incompleteWork.mode & ProfileMode) !== NoMode) { |
| 3367 | // Record the render duration for the fiber that errored. |
| 3368 | stopProfilerTimerIfRunningAndRecordIncompleteDuration(incompleteWork); |
| 3369 | |
| 3370 | // Include the time spent working on failed children before continuing. |
| 3371 | let actualDuration = incompleteWork.actualDuration; |
| 3372 | let child = incompleteWork.child; |
| 3373 | while (child !== null) { |
| 3374 | // $FlowFixMe[unsafe-addition] addition with possible null/undefined value |
| 3375 | actualDuration += child.actualDuration; |
| 3376 | child = child.sibling; |
| 3377 | } |
| 3378 | incompleteWork.actualDuration = actualDuration; |
| 3379 | } |
| 3380 | |
| 3381 | // TODO: Once we stop prerendering siblings, instead of resetting the parent |
| 3382 | // of the node being unwound, we should be able to reset node itself as we |
| 3383 | // unwind the stack. Saves an additional null check. |
| 3384 | const returnFiber = incompleteWork.return; |
| 3385 | if (returnFiber !== null) { |
| 3386 | // Mark the parent fiber as incomplete and clear its subtree flags. |
| 3387 | // TODO: Once we stop prerendering siblings, we may be able to get rid of |
| 3388 | // the Incomplete flag because unwinding to the nearest boundary will |
| 3389 | // happen synchronously. |
| 3390 | returnFiber.flags |= Incomplete; |
| 3391 | returnFiber.subtreeFlags = NoFlags; |
| 3392 | returnFiber.deletions = null; |
| 3393 | } |
| 3394 | |
| 3395 | if (!skipSiblings) { |
no test coverage detected