@@ -310,11 +310,18 @@ let workInProgress: Fiber | null = null;
310310// The lanes we're rendering
311311let workInProgressRootRenderLanes : Lanes = NoLanes ;
312312
313+ opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 ;
314+ const NotSuspended : SuspendedReason = 0 ;
315+ const SuspendedOnError : SuspendedReason = 1 ;
316+ // const SuspendedOnData: SuspendedReason = 2;
317+ const SuspendedOnImmediate : SuspendedReason = 3 ;
318+ const SuspendedAndReadyToUnwind : SuspendedReason = 4 ;
319+
313320// When this is true, the work-in-progress fiber just suspended (or errored) and
314321// we've yet to unwind the stack. In some cases, we may yield to the main thread
315322// after this happens. If the fiber is pinged before we resume, we can retry
316323// immediately instead of unwinding the stack.
317- let workInProgressIsSuspended : boolean = false ;
324+ let workInProgressSuspendedReason : SuspendedReason = NotSuspended ;
318325let workInProgressThrownValue : mixed = null ;
319326let workInProgressSuspendedThenableState : ThenableState | null = null ;
320327
@@ -1676,9 +1683,10 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
16761683 }
16771684
16781685 if ( workInProgress !== null ) {
1679- let interruptedWork = workInProgressIsSuspended
1680- ? workInProgress
1681- : workInProgress . return ;
1686+ let interruptedWork =
1687+ workInProgressSuspendedReason === NotSuspended
1688+ ? workInProgress . return
1689+ : workInProgress ;
16821690 while ( interruptedWork !== null ) {
16831691 const current = interruptedWork . alternate ;
16841692 unwindInterruptedWork (
@@ -1693,7 +1701,7 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
16931701 const rootWorkInProgress = createWorkInProgress ( root . current , null ) ;
16941702 workInProgress = rootWorkInProgress ;
16951703 workInProgressRootRenderLanes = renderLanes = lanes ;
1696- workInProgressIsSuspended = false ;
1704+ workInProgressSuspendedReason = NotSuspended ;
16971705 workInProgressThrownValue = null ;
16981706 workInProgressSuspendedThenableState = null ;
16991707 workInProgressRootDidAttachPingListener = false ;
@@ -1732,17 +1740,27 @@ function handleThrow(root, thrownValue): void {
17321740 // deprecate the old API in favor of `use`.
17331741 thrownValue = getSuspendedThenable ( ) ;
17341742 workInProgressSuspendedThenableState = getThenableStateAfterSuspending ( ) ;
1743+ workInProgressSuspendedReason = SuspendedOnImmediate ;
17351744 } else {
17361745 // This is a regular error. If something earlier in the component already
17371746 // suspended, we must clear the thenable state to unblock the work loop.
17381747 workInProgressSuspendedThenableState = null ;
1748+
1749+ const isWakeable =
1750+ thrownValue !== null &&
1751+ typeof thrownValue === 'object' &&
1752+ // $FlowFixMe[method-unbinding]
1753+ typeof thrownValue . then === 'function' ;
1754+
1755+ workInProgressSuspendedReason = isWakeable
1756+ ? // A wakeable object was thrown by a legacy Suspense implementation.
1757+ // This has slightly different behavior than suspending with `use`.
1758+ SuspendedAndReadyToUnwind
1759+ : // This is a regular error. If something earlier in the component already
1760+ // suspended, we must clear the thenable state to unblock the work loop.
1761+ SuspendedOnError ;
17391762 }
17401763
1741- // Setting this to `true` tells the work loop to unwind the stack instead
1742- // of entering the begin phase. It's called "suspended" because it usually
1743- // happens because of Suspense, but it also applies to errors. Think of it
1744- // as suspending the execution of the work loop.
1745- workInProgressIsSuspended = true ;
17461764 workInProgressThrownValue = thrownValue ;
17471765
17481766 const erroredWork = workInProgress ;
@@ -1762,12 +1780,7 @@ function handleThrow(root, thrownValue): void {
17621780
17631781 if ( enableSchedulingProfiler ) {
17641782 markComponentRenderStopped ( ) ;
1765- if (
1766- thrownValue !== null &&
1767- typeof thrownValue === 'object' &&
1768- // $FlowFixMe[method-unbinding]
1769- typeof thrownValue . then === 'function'
1770- ) {
1783+ if ( workInProgressSuspendedReason !== SuspendedOnError ) {
17711784 const wakeable : Wakeable = ( thrownValue : any ) ;
17721785 markComponentSuspended (
17731786 erroredWork ,
@@ -1968,11 +1981,11 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) {
19681981function workLoopSync ( ) {
19691982 // Perform work without checking if we need to yield between fiber.
19701983
1971- if ( workInProgressIsSuspended ) {
1984+ if ( workInProgressSuspendedReason !== NotSuspended ) {
19721985 // The current work-in-progress was already attempted. We need to unwind
19731986 // it before we continue the normal work loop.
19741987 const thrownValue = workInProgressThrownValue ;
1975- workInProgressIsSuspended = false ;
1988+ workInProgressSuspendedReason = NotSuspended ;
19761989 workInProgressThrownValue = null ;
19771990 if ( workInProgress !== null ) {
19781991 resumeSuspendedUnitOfWork ( workInProgress , thrownValue ) ;
@@ -2079,11 +2092,11 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
20792092function workLoopConcurrent ( ) {
20802093 // Perform work until Scheduler asks us to yield
20812094
2082- if ( workInProgressIsSuspended ) {
2095+ if ( workInProgressSuspendedReason !== NotSuspended ) {
20832096 // The current work-in-progress was already attempted. We need to unwind
20842097 // it before we continue the normal work loop.
20852098 const thrownValue = workInProgressThrownValue ;
2086- workInProgressIsSuspended = false ;
2099+ workInProgressSuspendedReason = NotSuspended ;
20872100 workInProgressThrownValue = null ;
20882101 if ( workInProgress !== null ) {
20892102 resumeSuspendedUnitOfWork ( workInProgress , thrownValue ) ;
0 commit comments