Skip to content

Commit 800d8c3

Browse files
committed
Track the largest suspense config expiration separately
This ensures that if we've scheduled lower pri work that doesn't have a suspenseConfig, we don't consider its expiration as the timeout.
1 parent b053a93 commit 800d8c3

File tree

1 file changed

+18
-15
lines changed

1 file changed

+18
-15
lines changed

packages/react-reconciler/src/ReactFiberScheduler.js

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
214214
let workInProgressRootLatestProcessedExpirationTime: ExpirationTime = Sync;
215+
let workInProgressRootLatestSuspenseTimeout: ExpirationTime = Sync;
215216
let workInProgressRootCanSuspendUsingConfig: null | SuspenseConfig = null;
216217

217218
let 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

19761976
function 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

20092009
function 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

Comments
 (0)