Skip to content

Commit 62dabe5

Browse files
committed
Throttle retries even if everything has loaded (#26611)
If a Suspense fallback is shown, and the data finishes loading really quickly after that, we throttle the content from appearing for 500ms to reduce thrash. This already works for successive fallback states (like if one fallback is nested inside another) but it wasn't being applied to the final step in the sequence: if there were no more unresolved Suspense boundaries in the tree, the content would appear immediately. This fixes the throttling behavior so that it applies to all renders that are the result of suspended data being loaded. (Our internal jargon term for this is a "retry".) DiffTrain build for [8256781](8256781)
1 parent bdb1083 commit 62dabe5

18 files changed

+900
-1316
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6b90976bc10f325146b193286435a4b5015ef605
1+
8256781fdf3ae1947a7f27ddc78ae11b9989c2cd

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (
2727
}
2828
"use strict";
2929

30-
var ReactVersion = "18.3.0-www-modern-54376ec8";
30+
var ReactVersion = "18.3.0-www-modern-ad6e07a1";
3131

3232
// ATTENTION
3333
// When adding new symbols to this file,

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 65 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
6969
return self;
7070
}
7171

72-
var ReactVersion = "18.3.0-www-classic-d940bd0e";
72+
var ReactVersion = "18.3.0-www-classic-3684ffc4";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -24184,109 +24184,89 @@ function queueRecoverableErrors(errors) {
2418424184
}
2418524185

2418624186
function finishConcurrentRender(root, exitStatus, finishedWork, lanes) {
24187+
// TODO: The fact that most of these branches are identical suggests that some
24188+
// of the exit statuses are not best modeled as exit statuses and should be
24189+
// tracked orthogonally.
2418724190
switch (exitStatus) {
2418824191
case RootInProgress:
2418924192
case RootFatalErrored: {
2419024193
throw new Error("Root did not complete. This is a bug in React.");
2419124194
}
2419224195

24193-
case RootErrored: {
24194-
// We should have already attempted to retry this tree. If we reached
24195-
// this point, it errored again. Commit it.
24196-
commitRootWhenReady(
24197-
root,
24198-
finishedWork,
24199-
workInProgressRootRecoverableErrors,
24200-
workInProgressTransitions,
24201-
lanes
24202-
);
24203-
break;
24204-
}
24205-
24206-
case RootSuspended: {
24207-
markRootSuspended(root, lanes); // We have an acceptable loading state. We need to figure out if we
24208-
// should immediately commit it or wait a bit.
24209-
24210-
if (
24211-
includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope
24212-
!shouldForceFlushFallbacksInDEV()
24213-
) {
24214-
// This render only included retries, no updates. Throttle committing
24215-
// retries so that we don't show too many loading states too quickly.
24216-
var msUntilTimeout =
24217-
globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now$1(); // Don't bother with a very short suspense time.
24218-
24219-
if (msUntilTimeout > 10) {
24220-
var nextLanes = getNextLanes(root, NoLanes);
24221-
24222-
if (nextLanes !== NoLanes) {
24223-
// There's additional work on this root.
24224-
break;
24225-
} // The render is suspended, it hasn't timed out, and there's no
24226-
// lower priority work to do. Instead of committing the fallback
24227-
// immediately, wait for more data to arrive.
24228-
24229-
root.timeoutHandle = scheduleTimeout(
24230-
commitRootWhenReady.bind(
24231-
null,
24232-
root,
24233-
finishedWork,
24234-
workInProgressRootRecoverableErrors,
24235-
workInProgressTransitions,
24236-
lanes
24237-
),
24238-
msUntilTimeout
24239-
);
24240-
break;
24241-
}
24242-
} // The work expired. Commit immediately.
24243-
24244-
commitRootWhenReady(
24245-
root,
24246-
finishedWork,
24247-
workInProgressRootRecoverableErrors,
24248-
workInProgressTransitions,
24249-
lanes
24250-
);
24251-
break;
24252-
}
24253-
2425424196
case RootSuspendedWithDelay: {
24255-
markRootSuspended(root, lanes);
24256-
2425724197
if (includesOnlyTransitions(lanes)) {
2425824198
// This is a transition, so we should exit without committing a
2425924199
// placeholder and without scheduling a timeout. Delay indefinitely
2426024200
// until we receive more data.
24261-
break;
24201+
markRootSuspended(root, lanes);
24202+
return;
2426224203
} // Commit the placeholder.
2426324204

24264-
commitRootWhenReady(
24265-
root,
24266-
finishedWork,
24267-
workInProgressRootRecoverableErrors,
24268-
workInProgressTransitions,
24269-
lanes
24270-
);
2427124205
break;
2427224206
}
2427324207

24208+
case RootErrored:
24209+
case RootSuspended:
2427424210
case RootCompleted: {
24275-
// The work completed.
24276-
commitRootWhenReady(
24277-
root,
24278-
finishedWork,
24279-
workInProgressRootRecoverableErrors,
24280-
workInProgressTransitions,
24281-
lanes
24282-
);
2428324211
break;
2428424212
}
2428524213

2428624214
default: {
2428724215
throw new Error("Unknown root exit status.");
2428824216
}
2428924217
}
24218+
24219+
if (shouldForceFlushFallbacksInDEV()) {
24220+
// We're inside an `act` scope. Commit immediately.
24221+
commitRoot(
24222+
root,
24223+
workInProgressRootRecoverableErrors,
24224+
workInProgressTransitions
24225+
);
24226+
} else {
24227+
if (includesOnlyRetries(lanes)) {
24228+
// This render only included retries, no updates. Throttle committing
24229+
// retries so that we don't show too many loading states too quickly.
24230+
var msUntilTimeout =
24231+
globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now$1(); // Don't bother with a very short suspense time.
24232+
24233+
if (msUntilTimeout > 10) {
24234+
markRootSuspended(root, lanes);
24235+
var nextLanes = getNextLanes(root, NoLanes);
24236+
24237+
if (nextLanes !== NoLanes) {
24238+
// There's additional work we can do on this root. We might as well
24239+
// attempt to work on that while we're suspended.
24240+
return;
24241+
} // The render is suspended, it hasn't timed out, and there's no
24242+
// lower priority work to do. Instead of committing the fallback
24243+
// immediately, wait for more data to arrive.
24244+
// TODO: Combine retry throttling with Suspensey commits. Right now they
24245+
// run one after the other.
24246+
24247+
root.timeoutHandle = scheduleTimeout(
24248+
commitRootWhenReady.bind(
24249+
null,
24250+
root,
24251+
finishedWork,
24252+
workInProgressRootRecoverableErrors,
24253+
workInProgressTransitions,
24254+
lanes
24255+
),
24256+
msUntilTimeout
24257+
);
24258+
return;
24259+
}
24260+
}
24261+
24262+
commitRootWhenReady(
24263+
root,
24264+
finishedWork,
24265+
workInProgressRootRecoverableErrors,
24266+
workInProgressTransitions,
24267+
lanes
24268+
);
24269+
}
2429024270
}
2429124271

2429224272
function commitRootWhenReady(
@@ -24296,6 +24276,8 @@ function commitRootWhenReady(
2429624276
transitions,
2429724277
lanes
2429824278
) {
24279+
// TODO: Combine retry throttling with Suspensey commits. Right now they run
24280+
// one after the other.
2429924281
if (includesOnlyNonUrgentLanes(lanes)) {
2430024282
// the suspensey resources. The renderer is responsible for accumulating
2430124283
// all the load events. This all happens in a single synchronous
@@ -24315,22 +24297,14 @@ function commitRootWhenReady(
2431524297
// us that it's ready. This will be canceled if we start work on the
2431624298
// root again.
2431724299
root.cancelPendingCommit = schedulePendingCommit(
24318-
commitRoot.bind(
24319-
null,
24320-
root,
24321-
workInProgressRootRecoverableErrors,
24322-
workInProgressTransitions
24323-
)
24300+
commitRoot.bind(null, root, recoverableErrors, transitions)
2432424301
);
24302+
markRootSuspended(root, lanes);
2432524303
return;
2432624304
}
2432724305
} // Otherwise, commit immediately.
2432824306

24329-
commitRoot(
24330-
root,
24331-
workInProgressRootRecoverableErrors,
24332-
workInProgressTransitions
24333-
);
24307+
commitRoot(root, recoverableErrors, transitions);
2433424308
}
2433524309

2433624310
function isRenderConsistentWithExternalStores(finishedWork) {

0 commit comments

Comments
 (0)