@samitouri / QOS-React-2 / commits / 970fa122d8

Use lanes to check if a render is a Suspense retry (#19307)

Now that Suspense retries have their own dedicated set of lanes (#19287), we can determine if a render includes only retries by checking if its lanes are a subset of the retry lanes. Previously we inferred this by checking `workInProgressRootLatestProcessedEventTime`. If it's not set, that implies that no updates were processed in the current render, which implies it must be a Suspense retry. The eventual plan is to get rid of `workInProgressRootLatestProcessedEventTime` and instead track event times on the root; this change is one the steps toward that goal. The relevant tests were originally added in #15769.

Andrew Clark committed Jul 10, 2020 at 08:58 UTC 970fa122d8188bafa600e9b5214833487fbf1092
3 files changed +18 -31
packages/react-reconciler/src/ReactFiberLane.js
+4 -1
@@ -451,9 +451,12 @@ export function getLanesToRetrySynchronouslyOnError(root: FiberRoot): Lanes {
451 export function returnNextLanesPriority() {
452 return return_highestLanePriority;
453 }
454 -export function hasUpdatePriority(lanes: Lanes) {
454 +export function includesNonIdleWork(lanes: Lanes) {
455 return (lanes & NonIdleLanes) !== NoLanes;
456 }
457 +export function includesOnlyRetries(lanes: Lanes) {
458 + return (lanes & RetryLanes) === lanes;
459 +}
460
461 // To ensure consistency across multiple updates in the same event, this should
462 // be a pure function, so that it always returns the same lane for given inputs.
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+7 -15
@@ -132,7 +132,8 @@ import {
132 removeLanes,
133 pickArbitraryLane,
134 hasDiscreteLanes,
135 - hasUpdatePriority,
135 + includesNonIdleWork,
136 + includesOnlyRetries,
137 getNextLanes,
138 returnNextLanesPriority,
139 setCurrentUpdateLanePriority,
@@ -847,22 +848,13 @@ function finishConcurrentRender(root, finishedWork, exitStatus, lanes) {
848 // We have an acceptable loading state. We need to figure out if we
849 // should immediately commit it or wait a bit.
850
850 - // If we have processed new updates during this render, we may now
851 - // have a new loading state ready. We want to ensure that we commit
852 - // that as soon as possible.
853 - const hasNotProcessedNewUpdates =
854 - workInProgressRootLatestProcessedEventTime === NoTimestamp;
851 if (
856 - hasNotProcessedNewUpdates &&
852 + includesOnlyRetries(lanes) &&
853 // do not delay if we're inside an act() scope
854 !shouldForceFlushFallbacksInDEV()
855 ) {
860 - // If we have not processed any new updates during this pass, then
861 - // this is either a retry of an existing fallback state or a
862 - // hidden tree. Hidden trees shouldn't be batched with other work
863 - // and after that's fixed it can only be a retry. We're going to
864 - // throttle committing retries so that we don't show too many
865 - // loading states too quickly.
856 + // This render only included retries, no updates. Throttle committing
857 + // retries so that we don't show too many loading states too quickly.
858 const msUntilTimeout =
859 globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();
860 // Don't bother with a very short suspense time.
@@ -1475,8 +1467,8 @@ export function renderDidSuspendDelayIfPossible(): void {
1467 // this render.
1468 if (
1469 workInProgressRoot !== null &&
1478 - (hasUpdatePriority(workInProgressRootSkippedLanes) ||
1479 - hasUpdatePriority(workInProgressRootUpdatedLanes))
1470 + (includesNonIdleWork(workInProgressRootSkippedLanes) ||
1471 + includesNonIdleWork(workInProgressRootUpdatedLanes))
1472 ) {
1473 // Mark the current render as suspended so that we switch to working on
1474 // the updates that were skipped. Usually we only suspend at the end of
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+7 -15
@@ -155,7 +155,8 @@ import {
155 removeLanes,
156 pickArbitraryLane,
157 hasDiscreteLanes,
158 - hasUpdatePriority,
158 + includesNonIdleWork,
159 + includesOnlyRetries,
160 getNextLanes,
161 returnNextLanesPriority,
162 setCurrentUpdateLanePriority,
@@ -870,22 +871,13 @@ function finishConcurrentRender(root, finishedWork, exitStatus, lanes) {
871 // We have an acceptable loading state. We need to figure out if we
872 // should immediately commit it or wait a bit.
873
873 - // If we have processed new updates during this render, we may now
874 - // have a new loading state ready. We want to ensure that we commit
875 - // that as soon as possible.
876 - const hasNotProcessedNewUpdates =
877 - workInProgressRootLatestProcessedEventTime === NoTimestamp;
874 if (
879 - hasNotProcessedNewUpdates &&
875 + includesOnlyRetries(lanes) &&
876 // do not delay if we're inside an act() scope
877 !shouldForceFlushFallbacksInDEV()
878 ) {
883 - // If we have not processed any new updates during this pass, then
884 - // this is either a retry of an existing fallback state or a
885 - // hidden tree. Hidden trees shouldn't be batched with other work
886 - // and after that's fixed it can only be a retry. We're going to
887 - // throttle committing retries so that we don't show too many
888 - // loading states too quickly.
879 + // This render only included retries, no updates. Throttle committing
880 + // retries so that we don't show too many loading states too quickly.
881 const msUntilTimeout =
882 globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();
883 // Don't bother with a very short suspense time.
@@ -1498,8 +1490,8 @@ export function renderDidSuspendDelayIfPossible(): void {
1490 // this render.
1491 if (
1492 workInProgressRoot !== null &&
1501 - (hasUpdatePriority(workInProgressRootSkippedLanes) ||
1502 - hasUpdatePriority(workInProgressRootUpdatedLanes))
1493 + (includesNonIdleWork(workInProgressRootSkippedLanes) ||
1494 + includesNonIdleWork(workInProgressRootUpdatedLanes))
1495 ) {
1496 // Mark the current render as suspended so that we switch to working on
1497 // the updates that were skipped. Usually we only suspend at the end of