@@ -310,11 +310,18 @@ let workInProgress: Fiber | null = null;
310
310
// The lanes we're rendering
311
311
let workInProgressRootRenderLanes : Lanes = NoLanes ;
312
312
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
+
313
320
// When this is true, the work-in-progress fiber just suspended (or errored) and
314
321
// we've yet to unwind the stack. In some cases, we may yield to the main thread
315
322
// after this happens. If the fiber is pinged before we resume, we can retry
316
323
// immediately instead of unwinding the stack.
317
- let workInProgressIsSuspended : boolean = false ;
324
+ let workInProgressSuspendedReason : SuspendedReason = NotSuspended ;
318
325
let workInProgressThrownValue : mixed = null ;
319
326
let workInProgressSuspendedThenableState : ThenableState | null = null ;
320
327
@@ -1676,9 +1683,10 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
1676
1683
}
1677
1684
1678
1685
if ( workInProgress !== null ) {
1679
- let interruptedWork = workInProgressIsSuspended
1680
- ? workInProgress
1681
- : workInProgress . return ;
1686
+ let interruptedWork =
1687
+ workInProgressSuspendedReason === NotSuspended
1688
+ ? workInProgress . return
1689
+ : workInProgress ;
1682
1690
while ( interruptedWork !== null ) {
1683
1691
const current = interruptedWork . alternate ;
1684
1692
unwindInterruptedWork (
@@ -1693,7 +1701,7 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
1693
1701
const rootWorkInProgress = createWorkInProgress ( root . current , null ) ;
1694
1702
workInProgress = rootWorkInProgress ;
1695
1703
workInProgressRootRenderLanes = renderLanes = lanes ;
1696
- workInProgressIsSuspended = false ;
1704
+ workInProgressSuspendedReason = NotSuspended ;
1697
1705
workInProgressThrownValue = null ;
1698
1706
workInProgressSuspendedThenableState = null ;
1699
1707
workInProgressRootDidAttachPingListener = false ;
@@ -1732,17 +1740,27 @@ function handleThrow(root, thrownValue): void {
1732
1740
// deprecate the old API in favor of `use`.
1733
1741
thrownValue = getSuspendedThenable ( ) ;
1734
1742
workInProgressSuspendedThenableState = getThenableStateAfterSuspending ( ) ;
1743
+ workInProgressSuspendedReason = SuspendedOnImmediate ;
1735
1744
} else {
1736
1745
// This is a regular error. If something earlier in the component already
1737
1746
// suspended, we must clear the thenable state to unblock the work loop.
1738
1747
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 ;
1739
1762
}
1740
1763
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 ;
1746
1764
workInProgressThrownValue = thrownValue ;
1747
1765
1748
1766
const erroredWork = workInProgress ;
@@ -1762,12 +1780,7 @@ function handleThrow(root, thrownValue): void {
1762
1780
1763
1781
if ( enableSchedulingProfiler ) {
1764
1782
markComponentRenderStopped ( ) ;
1765
- if (
1766
- thrownValue !== null &&
1767
- typeof thrownValue === 'object' &&
1768
- // $FlowFixMe[method-unbinding]
1769
- typeof thrownValue . then === 'function'
1770
- ) {
1783
+ if ( workInProgressSuspendedReason !== SuspendedOnError ) {
1771
1784
const wakeable : Wakeable = ( thrownValue : any ) ;
1772
1785
markComponentSuspended (
1773
1786
erroredWork ,
@@ -1968,11 +1981,11 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) {
1968
1981
function workLoopSync ( ) {
1969
1982
// Perform work without checking if we need to yield between fiber.
1970
1983
1971
- if ( workInProgressIsSuspended ) {
1984
+ if ( workInProgressSuspendedReason !== NotSuspended ) {
1972
1985
// The current work-in-progress was already attempted. We need to unwind
1973
1986
// it before we continue the normal work loop.
1974
1987
const thrownValue = workInProgressThrownValue ;
1975
- workInProgressIsSuspended = false ;
1988
+ workInProgressSuspendedReason = NotSuspended ;
1976
1989
workInProgressThrownValue = null ;
1977
1990
if ( workInProgress !== null ) {
1978
1991
resumeSuspendedUnitOfWork ( workInProgress , thrownValue ) ;
@@ -2079,11 +2092,11 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
2079
2092
function workLoopConcurrent ( ) {
2080
2093
// Perform work until Scheduler asks us to yield
2081
2094
2082
- if ( workInProgressIsSuspended ) {
2095
+ if ( workInProgressSuspendedReason !== NotSuspended ) {
2083
2096
// The current work-in-progress was already attempted. We need to unwind
2084
2097
// it before we continue the normal work loop.
2085
2098
const thrownValue = workInProgressThrownValue ;
2086
- workInProgressIsSuspended = false ;
2099
+ workInProgressSuspendedReason = NotSuspended ;
2087
2100
workInProgressThrownValue = null ;
2088
2101
if ( workInProgress !== null ) {
2089
2102
resumeSuspendedUnitOfWork ( workInProgress , thrownValue ) ;
0 commit comments