@@ -212,6 +212,7 @@ let workInProgressRootExitStatus: RootExitStatus = RootIncomplete;
212212// because we deal mostly with expiration times in the hot path, so this avoids
213213// the conversion happening in the hot path.
214214let workInProgressRootLatestProcessedExpirationTime : ExpirationTime = Sync ;
215+ let workInProgressRootLatestSuspenseTimeout : ExpirationTime = Sync ;
215216let workInProgressRootCanSuspendUsingConfig : null | SuspenseConfig = null ;
216217
217218let nextEffect : Fiber | null = null ;
@@ -734,6 +735,7 @@ function prepareFreshStack(root, expirationTime) {
734735 renderExpirationTime = expirationTime ;
735736 workInProgressRootExitStatus = RootIncomplete ;
736737 workInProgressRootLatestProcessedExpirationTime = Sync ;
738+ workInProgressRootLatestSuspenseTimeout = Sync ;
737739 workInProgressRootCanSuspendUsingConfig = null ;
738740
739741 if ( __DEV__ ) {
@@ -949,6 +951,7 @@ function renderRoot(
949951 workInProgressRootExitStatus === RootSuspendedWithDelay ;
950952 let msUntilTimeout = computeMsUntilTimeout (
951953 workInProgressRootLatestProcessedExpirationTime ,
954+ workInProgressRootLatestSuspenseTimeout ,
952955 expirationTime ,
953956 workInProgressRootCanSuspendUsingConfig ,
954957 shouldDelay ,
@@ -973,14 +976,14 @@ function renderRoot(
973976 // The work completed. Ready to commit.
974977 if (
975978 ! isSync &&
976- workInProgressRootLatestProcessedExpirationTime !== Sync &&
979+ workInProgressRootLatestSuspenseTimeout !== Sync &&
977980 workInProgressRootCanSuspendUsingConfig !== null
978981 ) {
979982 // If we have exceeded the minimum loading delay, which probably
980983 // means we have shown a spinner already, we might have to suspend
981984 // a bit longer to ensure that the spinner is shown for enough time.
982985 const msUntilTimeout = computeMsUntilSuspenseLoadingDelay (
983- workInProgressRootLatestProcessedExpirationTime ,
986+ workInProgressRootLatestSuspenseTimeout ,
984987 expirationTime ,
985988 workInProgressRootCanSuspendUsingConfig ,
986989 ) ;
@@ -1011,15 +1014,12 @@ export function markRenderEventTimeAndConfig(
10111014 workInProgressRootLatestProcessedExpirationTime = expirationTime ;
10121015 }
10131016 if ( suspenseConfig !== null ) {
1014- // Most of the time we only have one config and getting wrong is not bad.
1015- // We pick the config with the lowest timeout because we'll use it to
1016- // reverse engineer the event time if we end up using JND and we want to
1017- // error on the side of suspending less time.
10181017 if (
1019- workInProgressRootCanSuspendUsingConfig === null ||
1020- workInProgressRootCanSuspendUsingConfig . timeoutMs <
1021- suspenseConfig . timeoutMs
1018+ expirationTime < workInProgressRootLatestSuspenseTimeout &&
1019+ expirationTime > Never
10221020 ) {
1021+ workInProgressRootLatestSuspenseTimeout = expirationTime ;
1022+ // Most of the time we only have one config and getting wrong is not bad.
10231023 workInProgressRootCanSuspendUsingConfig = suspenseConfig ;
10241024 }
10251025 }
@@ -1974,7 +1974,7 @@ function jnd(timeElapsed: number) {
19741974}
19751975
19761976function computeMsUntilSuspenseLoadingDelay (
1977- mostRecentEventTime : ExpirationTime ,
1977+ latestTimeout : ExpirationTime ,
19781978 committedExpirationTime : ExpirationTime ,
19791979 suspenseConfig : SuspenseConfig ,
19801980) {
@@ -1992,7 +1992,7 @@ function computeMsUntilSuspenseLoadingDelay(
19921992 // Compute the time until this render pass would expire.
19931993 const currentTimeMs : number = now ( ) ;
19941994 const eventTimeMs : number = inferTimeFromExpirationTime (
1995- mostRecentEventTime ,
1995+ latestTimeout ,
19961996 suspenseConfig ,
19971997 ) ;
19981998 const timeElapsed = currentTimeMs - eventTimeMs ;
@@ -2008,6 +2008,7 @@ function computeMsUntilSuspenseLoadingDelay(
20082008
20092009function computeMsUntilTimeout (
20102010 mostRecentEventTime : ExpirationTime ,
2011+ suspenseTimeout : ExpirationTime ,
20112012 committedExpirationTime : ExpirationTime ,
20122013 suspenseConfig : null | SuspenseConfig ,
20132014 shouldDelay : boolean ,
@@ -2019,17 +2020,19 @@ function computeMsUntilTimeout(
20192020
20202021 // Compute the time until this render pass would expire.
20212022 const currentTimeMs : number = now ( ) ;
2022- const timeUntilExpirationMs =
2023- expirationTimeToMs ( committedExpirationTime ) - currentTimeMs ;
20242023
2025- if ( suspenseConfig !== null && shouldDelay ) {
2026- return timeUntilExpirationMs ;
2024+ if ( suspenseTimeout !== Sync && shouldDelay ) {
2025+ const timeUntilTimeoutMs =
2026+ expirationTimeToMs ( suspenseTimeout ) - currentTimeMs ;
2027+ return timeUntilTimeoutMs ;
20272028 }
20282029
20292030 const eventTimeMs : number = inferTimeFromExpirationTime (
20302031 mostRecentEventTime ,
20312032 suspenseConfig ,
20322033 ) ;
2034+ const timeUntilExpirationMs =
2035+ expirationTimeToMs ( committedExpirationTime ) - currentTimeMs ;
20332036 let timeElapsed = currentTimeMs - eventTimeMs ;
20342037 if ( timeElapsed < 0 ) {
20352038 // We get this wrong some time since we estimate the time.
0 commit comments