@samitouri / QOS-React / commits / cae764ce81

Revert "[Re-land] Make prerendering always non-blocking (#31268)" (#31355)

This reverts commit 6c4bbc783286bf6eebd9927cb52e8fec5ad4dd74. It looked like the bug we found on the original land was related to broken product code. But through landing #31268 we found additional bugs internally. Since disabling the feature flag does not fix the bugs, we have to revert again to unblock the sync. We can continue to debug with our internal build.

Jack Pope committed Oct 25, 2024 at 09:17 UTC cae764ce81b1bd6c418e9e23651794b6b09208e8
6 files changed +126 -278
packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js
+1 -1
@@ -744,7 +744,7 @@ describe('ReactDOMFiberAsync', () => {
744 // Because it suspended, it remains on the current path
745 expect(div.textContent).toBe('/path/a');
746 });
747 - assertLog(gate('enableSiblingPrerendering') ? ['Suspend! [/path/b]'] : []);
747 + assertLog([]);
748
749 await act(async () => {
750 resolvePromise();
packages/react-reconciler/src/ReactFiberLane.js
+2 -4
@@ -765,14 +765,12 @@ export function markRootSuspended(
765 root: FiberRoot,
766 suspendedLanes: Lanes,
767 spawnedLane: Lane,
768 - didAttemptEntireTree: boolean,
768 + didSkipSuspendedSiblings: boolean,
769 ) {
770 - // TODO: Split this into separate functions for marking the root at the end of
771 - // a render attempt versus suspending while the root is still in progress.
770 root.suspendedLanes |= suspendedLanes;
771 root.pingedLanes &= ~suspendedLanes;
772
775 - if (enableSiblingPrerendering && didAttemptEntireTree) {
773 + if (enableSiblingPrerendering && !didSkipSuspendedSiblings) {
774 // Mark these lanes as warm so we know there's nothing else to work on.
775 root.warmLanes |= suspendedLanes;
776 } else {
packages/react-reconciler/src/ReactFiberRootScheduler.js
+4 -16
@@ -18,7 +18,6 @@ import {
18 disableSchedulerTimeoutInWorkLoop,
19 enableProfilerTimer,
20 enableProfilerNestedUpdatePhase,
21 - enableSiblingPrerendering,
21 } from 'shared/ReactFeatureFlags';
22 import {
23 NoLane,
@@ -30,7 +29,6 @@ import {
29 markStarvedLanesAsExpired,
30 claimNextTransitionLane,
31 getNextLanesToFlushSync,
33 - checkIfRootIsPrerendering,
32 } from './ReactFiberLane';
33 import {
34 CommitContext,
@@ -208,10 +206,7 @@ function flushSyncWorkAcrossRoots_impl(
206 ? workInProgressRootRenderLanes
207 : NoLanes,
208 );
211 - if (
212 - includesSyncLane(nextLanes) &&
213 - !checkIfRootIsPrerendering(root, nextLanes)
214 - ) {
209 + if (includesSyncLane(nextLanes)) {
210 // This root has pending sync work. Flush it now.
211 didPerformSomeWork = true;
212 performSyncWorkOnRoot(root, nextLanes);
@@ -346,13 +341,7 @@ function scheduleTaskForRootDuringMicrotask(
341 }
342
343 // Schedule a new callback in the host environment.
349 - if (
350 - includesSyncLane(nextLanes) &&
351 - // If we're prerendering, then we should use the concurrent work loop
352 - // even if the lanes are synchronous, so that prerendering never blocks
353 - // the main thread.
354 - !(enableSiblingPrerendering && checkIfRootIsPrerendering(root, nextLanes))
355 - ) {
344 + if (includesSyncLane(nextLanes)) {
345 // Synchronous work is always flushed at the end of the microtask, so we
346 // don't need to schedule an additional task.
347 if (existingCallbackNode !== null) {
@@ -386,10 +375,9 @@ function scheduleTaskForRootDuringMicrotask(
375
376 let schedulerPriorityLevel;
377 switch (lanesToEventPriority(nextLanes)) {
389 - // Scheduler does have an "ImmediatePriority", but now that we use
390 - // microtasks for sync work we no longer use that. Any sync work that
391 - // reaches this path is meant to be time sliced.
378 case DiscreteEventPriority:
379 + schedulerPriorityLevel = ImmediateSchedulerPriority;
380 + break;
381 case ContinuousEventPriority:
382 schedulerPriorityLevel = UserBlockingSchedulerPriority;
383 break;
packages/react-reconciler/src/ReactFiberWorkLoop.js
+119 -174
@@ -765,12 +765,11 @@ export function scheduleUpdateOnFiber(
765 // The incoming update might unblock the current render. Interrupt the
766 // current attempt and restart from the top.
767 prepareFreshStack(root, NoLanes);
768 - const didAttemptEntireTree = false;
768 markRootSuspended(
769 root,
770 workInProgressRootRenderLanes,
771 workInProgressDeferredLane,
773 - didAttemptEntireTree,
772 + workInProgressRootDidSkipSuspendedSiblings,
773 );
774 }
775
@@ -833,12 +832,11 @@ export function scheduleUpdateOnFiber(
832 // effect of interrupting the current render and switching to the update.
833 // TODO: Make sure this doesn't override pings that happen while we've
834 // already started rendering.
836 - const didAttemptEntireTree = false;
835 markRootSuspended(
836 root,
837 workInProgressRootRenderLanes,
838 workInProgressDeferredLane,
841 - didAttemptEntireTree,
839 + workInProgressRootDidSkipSuspendedSiblings,
840 );
841 }
842 }
@@ -900,120 +898,100 @@ export function performWorkOnRoot(
898 // for too long ("expired" work, to prevent starvation), or we're in
899 // sync-updates-by-default mode.
900 const shouldTimeSlice =
903 - (!forceSync &&
904 - !includesBlockingLane(lanes) &&
905 - !includesExpiredLane(root, lanes)) ||
906 - // If we're prerendering, then we should use the concurrent work loop
907 - // even if the lanes are synchronous, so that prerendering never blocks
908 - // the main thread.
909 - // TODO: We should consider doing this whenever a sync lane is suspended,
910 - // even for regular pings.
911 - (enableSiblingPrerendering && checkIfRootIsPrerendering(root, lanes));
912 -
901 + !forceSync &&
902 + !includesBlockingLane(lanes) &&
903 + !includesExpiredLane(root, lanes);
904 let exitStatus = shouldTimeSlice
905 ? renderRootConcurrent(root, lanes)
915 - : renderRootSync(root, lanes, true);
906 + : renderRootSync(root, lanes);
907
917 - do {
908 + if (exitStatus !== RootInProgress) {
909 let renderWasConcurrent = shouldTimeSlice;
919 - if (exitStatus === RootInProgress) {
920 - // Render phase is still in progress.
921 - if (
922 - enableSiblingPrerendering &&
923 - workInProgressRootIsPrerendering &&
924 - !shouldTimeSlice
925 - ) {
926 - // We're in prerendering mode, but time slicing is not enabled. This
927 - // happens when something suspends during a synchronous update. Exit the
928 - // the work loop. When we resume, we'll use the concurrent work loop so
929 - // that prerendering is non-blocking.
930 - //
931 - // Mark the root as suspended. Usually we do this at the end of the
932 - // render phase, but we do it here so that we resume in
933 - // prerendering mode.
934 - // TODO: Consider always calling markRootSuspended immediately.
935 - // Needs to be *after* we attach a ping listener, though.
936 - const didAttemptEntireTree = false;
937 - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree);
938 - }
939 - break;
940 - } else if (exitStatus === RootDidNotComplete) {
941 - // The render unwound without completing the tree. This happens in special
942 - // cases where need to exit the current render without producing a
943 - // consistent tree or committing.
944 - const didAttemptEntireTree = !workInProgressRootDidSkipSuspendedSiblings;
945 - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree);
946 - } else {
947 - // The render completed.
948 -
949 - // Check if this render may have yielded to a concurrent event, and if so,
950 - // confirm that any newly rendered stores are consistent.
951 - // TODO: It's possible that even a concurrent render may never have yielded
952 - // to the main thread, if it was fast enough, or if it expired. We could
953 - // skip the consistency check in that case, too.
954 - const finishedWork: Fiber = (root.current.alternate: any);
955 - if (
956 - renderWasConcurrent &&
957 - !isRenderConsistentWithExternalStores(finishedWork)
958 - ) {
959 - // A store was mutated in an interleaved event. Render again,
960 - // synchronously, to block further mutations.
961 - exitStatus = renderRootSync(root, lanes, false);
962 - // We assume the tree is now consistent because we didn't yield to any
963 - // concurrent events.
964 - renderWasConcurrent = false;
965 - // Need to check the exit status again.
966 - continue;
967 - }
968 -
969 - // Check if something threw
970 - if (
971 - (disableLegacyMode || root.tag !== LegacyRoot) &&
972 - exitStatus === RootErrored
973 - ) {
974 - const lanesThatJustErrored = lanes;
975 - const errorRetryLanes = getLanesToRetrySynchronouslyOnError(
910 + do {
911 + if (exitStatus === RootDidNotComplete) {
912 + // The render unwound without completing the tree. This happens in special
913 + // cases where need to exit the current render without producing a
914 + // consistent tree or committing.
915 + markRootSuspended(
916 root,
977 - lanesThatJustErrored,
917 + lanes,
918 + NoLane,
919 + workInProgressRootDidSkipSuspendedSiblings,
920 );
979 - if (errorRetryLanes !== NoLanes) {
980 - lanes = errorRetryLanes;
981 - exitStatus = recoverFromConcurrentError(
921 + } else {
922 + // The render completed.
923 +
924 + // Check if this render may have yielded to a concurrent event, and if so,
925 + // confirm that any newly rendered stores are consistent.
926 + // TODO: It's possible that even a concurrent render may never have yielded
927 + // to the main thread, if it was fast enough, or if it expired. We could
928 + // skip the consistency check in that case, too.
929 + const finishedWork: Fiber = (root.current.alternate: any);
930 + if (
931 + renderWasConcurrent &&
932 + !isRenderConsistentWithExternalStores(finishedWork)
933 + ) {
934 + // A store was mutated in an interleaved event. Render again,
935 + // synchronously, to block further mutations.
936 + exitStatus = renderRootSync(root, lanes);
937 + // We assume the tree is now consistent because we didn't yield to any
938 + // concurrent events.
939 + renderWasConcurrent = false;
940 + // Need to check the exit status again.
941 + continue;
942 + }
943 +
944 + // Check if something threw
945 + if (
946 + (disableLegacyMode || root.tag !== LegacyRoot) &&
947 + exitStatus === RootErrored
948 + ) {
949 + const lanesThatJustErrored = lanes;
950 + const errorRetryLanes = getLanesToRetrySynchronouslyOnError(
951 root,
952 lanesThatJustErrored,
984 - errorRetryLanes,
953 );
986 - renderWasConcurrent = false;
987 - // Need to check the exit status again.
988 - if (exitStatus !== RootErrored) {
989 - // The root did not error this time. Restart the exit algorithm
990 - // from the beginning.
991 - // TODO: Refactor the exit algorithm to be less confusing. Maybe
992 - // more branches + recursion instead of a loop. I think the only
993 - // thing that causes it to be a loop is the RootDidNotComplete
994 - // check. If that's true, then we don't need a loop/recursion
995 - // at all.
996 - continue;
997 - } else {
998 - // The root errored yet again. Proceed to commit the tree.
954 + if (errorRetryLanes !== NoLanes) {
955 + lanes = errorRetryLanes;
956 + exitStatus = recoverFromConcurrentError(
957 + root,
958 + lanesThatJustErrored,
959 + errorRetryLanes,
960 + );
961 + renderWasConcurrent = false;
962 + // Need to check the exit status again.
963 + if (exitStatus !== RootErrored) {
964 + // The root did not error this time. Restart the exit algorithm
965 + // from the beginning.
966 + // TODO: Refactor the exit algorithm to be less confusing. Maybe
967 + // more branches + recursion instead of a loop. I think the only
968 + // thing that causes it to be a loop is the RootDidNotComplete
969 + // check. If that's true, then we don't need a loop/recursion
970 + // at all.
971 + continue;
972 + } else {
973 + // The root errored yet again. Proceed to commit the tree.
974 + }
975 }
976 }
1001 - }
1002 - if (exitStatus === RootFatalErrored) {
1003 - prepareFreshStack(root, NoLanes);
1004 - // Since this is a fatal error, we're going to pretend we attempted
1005 - // the entire tree, to avoid scheduling a prerender.
1006 - const didAttemptEntireTree = true;
1007 - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree);
1008 - break;
1009 - }
977 + if (exitStatus === RootFatalErrored) {
978 + prepareFreshStack(root, NoLanes);
979 + markRootSuspended(
980 + root,
981 + lanes,
982 + NoLane,
983 + workInProgressRootDidSkipSuspendedSiblings,
984 + );
985 + break;
986 + }
987
1011 - // We now have a consistent tree. The next step is either to commit it,
1012 - // or, if something suspended, wait to commit it after a timeout.
1013 - finishConcurrentRender(root, exitStatus, finishedWork, lanes);
1014 - }
1015 - break;
1016 - } while (true);
988 + // We now have a consistent tree. The next step is either to commit it,
989 + // or, if something suspended, wait to commit it after a timeout.
990 + finishConcurrentRender(root, exitStatus, finishedWork, lanes);
991 + }
992 + break;
993 + } while (true);
994 + }
995
996 ensureRootIsScheduled(root);
997 }
@@ -1046,7 +1024,7 @@ function recoverFromConcurrentError(
1024 rootWorkInProgress.flags |= ForceClientRender;
1025 }
1026
1049 - const exitStatus = renderRootSync(root, errorRetryLanes, false);
1027 + const exitStatus = renderRootSync(root, errorRetryLanes);
1028 if (exitStatus !== RootErrored) {
1029 // Successfully finished rendering on retry
1030
@@ -1130,13 +1108,11 @@ function finishConcurrentRender(
1108 // This is a transition, so we should exit without committing a
1109 // placeholder and without scheduling a timeout. Delay indefinitely
1110 // until we receive more data.
1133 - const didAttemptEntireTree =
1134 - !workInProgressRootDidSkipSuspendedSiblings;
1111 markRootSuspended(
1112 root,
1113 lanes,
1114 workInProgressDeferredLane,
1139 - didAttemptEntireTree,
1115 + workInProgressRootDidSkipSuspendedSiblings,
1116 );
1117 return;
1118 }
@@ -1192,13 +1168,11 @@ function finishConcurrentRender(
1168
1169 // Don't bother with a very short suspense time.
1170 if (msUntilTimeout > 10) {
1195 - const didAttemptEntireTree =
1196 - !workInProgressRootDidSkipSuspendedSiblings;
1171 markRootSuspended(
1172 root,
1173 lanes,
1174 workInProgressDeferredLane,
1201 - didAttemptEntireTree,
1175 + workInProgressRootDidSkipSuspendedSiblings,
1176 );
1177
1178 const nextLanes = getNextLanes(root, NoLanes);
@@ -1312,8 +1286,7 @@ function commitRootWhenReady(
1286 completedRenderEndTime,
1287 ),
1288 );
1315 - const didAttemptEntireTree = !didSkipSuspendedSiblings;
1316 - markRootSuspended(root, lanes, spawnedLane, didAttemptEntireTree);
1289 + markRootSuspended(root, lanes, spawnedLane, didSkipSuspendedSiblings);
1290 return;
1291 }
1292 }
@@ -1436,7 +1409,7 @@ function markRootSuspended(
1409 root: FiberRoot,
1410 suspendedLanes: Lanes,
1411 spawnedLane: Lane,
1439 - didAttemptEntireTree: boolean,
1412 + didSkipSuspendedSiblings: boolean,
1413 ) {
1414 // When suspending, we should always exclude lanes that were pinged or (more
1415 // rarely, since we try to avoid it) updated during the render phase.
@@ -1445,7 +1418,12 @@ function markRootSuspended(
1418 suspendedLanes,
1419 workInProgressRootInterleavedUpdatedLanes,
1420 );
1448 - _markRootSuspended(root, suspendedLanes, spawnedLane, didAttemptEntireTree);
1421 + _markRootSuspended(
1422 + root,
1423 + suspendedLanes,
1424 + spawnedLane,
1425 + didSkipSuspendedSiblings,
1426 + );
1427 }
1428
1429 export function flushRoot(root: FiberRoot, lanes: Lanes) {
@@ -1987,12 +1965,7 @@ export function renderDidSuspendDelayIfPossible(): void {
1965
1966 if (
1967 !workInProgressRootDidSkipSuspendedSiblings &&
1990 - // Check if the root will be blocked from committing.
1991 - // TODO: Consider aligning this better with the rest of the logic. Maybe
1992 - // we should only set the exit status to RootSuspendedWithDelay if this
1993 - // condition is true? And remove the equivalent checks elsewhere.
1994 - (includesOnlyTransitions(workInProgressRootRenderLanes) ||
1995 - getSuspenseHandler() === null)
1968 + !includesBlockingLane(workInProgressRootRenderLanes)
1969 ) {
1970 // This render may not have originally been scheduled as a prerender, but
1971 // something suspended inside the visible part of the tree, which means we
@@ -2018,12 +1991,11 @@ export function renderDidSuspendDelayIfPossible(): void {
1991 // pinged or updated while we were rendering.
1992 // TODO: Consider unwinding immediately, using the
1993 // SuspendedOnHydration mechanism.
2021 - const didAttemptEntireTree = false;
1994 markRootSuspended(
1995 workInProgressRoot,
1996 workInProgressRootRenderLanes,
1997 workInProgressDeferredLane,
2026 - didAttemptEntireTree,
1998 + workInProgressRootDidSkipSuspendedSiblings,
1999 );
2000 }
2001 }
@@ -2053,11 +2025,7 @@ export function renderHasNotSuspendedYet(): boolean {
2025 // TODO: Over time, this function and renderRootConcurrent have become more
2026 // and more similar. Not sure it makes sense to maintain forked paths. Consider
2027 // unifying them again.
2056 -function renderRootSync(
2057 - root: FiberRoot,
2058 - lanes: Lanes,
2059 - shouldYieldForPrerendering: boolean,
2060 -): RootExitStatus {
2028 +function renderRootSync(root: FiberRoot, lanes: Lanes) {
2029 const prevExecutionContext = executionContext;
2030 executionContext |= RenderContext;
2031 const prevDispatcher = pushDispatcher(root.containerInfo);
@@ -2097,7 +2065,6 @@ function renderRootSync(
2065 }
2066
2067 let didSuspendInShell = false;
2100 - let exitStatus = workInProgressRootExitStatus;
2068 outer: do {
2069 try {
2070 if (
@@ -2119,37 +2086,16 @@ function renderRootSync(
2086 // Selective hydration. An update flowed into a dehydrated tree.
2087 // Interrupt the current render so the work loop can switch to the
2088 // hydration lane.
2122 - // TODO: I think we might not need to reset the stack here; we can
2123 - // just yield and reset the stack when we re-enter the work loop,
2124 - // like normal.
2089 resetWorkInProgressStack();
2126 - exitStatus = RootDidNotComplete;
2090 + workInProgressRootExitStatus = RootDidNotComplete;
2091 break outer;
2092 }
2093 case SuspendedOnImmediate:
2130 - case SuspendedOnData:
2131 - case SuspendedOnDeprecatedThrowPromise: {
2132 - if (getSuspenseHandler() === null) {
2094 + case SuspendedOnData: {
2095 + if (!didSuspendInShell && getSuspenseHandler() === null) {
2096 didSuspendInShell = true;
2097 }
2135 - const reason = workInProgressSuspendedReason;
2136 - workInProgressSuspendedReason = NotSuspended;
2137 - workInProgressThrownValue = null;
2138 - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason);
2139 - if (
2140 - enableSiblingPrerendering &&
2141 - shouldYieldForPrerendering &&
2142 - workInProgressRootIsPrerendering
2143 - ) {
2144 - // We've switched into prerendering mode. This implies that we
2145 - // suspended outside of a Suspense boundary, which means this
2146 - // render will be blocked from committing. Yield to the main
2147 - // thread so we can switch to prerendering using the concurrent
2148 - // work loop.
2149 - exitStatus = RootInProgress;
2150 - break outer;
2151 - }
2152 - break;
2098 + // Intentional fallthrough
2099 }
2100 default: {
2101 // Unwind then continue with the normal work loop.
@@ -2162,7 +2108,6 @@ function renderRootSync(
2108 }
2109 }
2110 workLoopSync();
2165 - exitStatus = workInProgressRootExitStatus;
2111 break;
2112 } catch (thrownValue) {
2113 handleThrow(root, thrownValue);
@@ -2185,6 +2130,14 @@ function renderRootSync(
2130 popDispatcher(prevDispatcher);
2131 popAsyncDispatcher(prevAsyncDispatcher);
2132
2133 + if (workInProgress !== null) {
2134 + // This is a sync render, so we should have finished the whole tree.
2135 + throw new Error(
2136 + 'Cannot commit an incomplete root. This error is likely caused by a ' +
2137 + 'bug in React. Please file an issue.',
2138 + );
2139 + }
2140 +
2141 if (__DEV__) {
2142 if (enableDebugTracing) {
2143 logRenderStopped();
@@ -2195,21 +2148,14 @@ function renderRootSync(
2148 markRenderStopped();
2149 }
2150
2198 - if (workInProgress !== null) {
2199 - // Did not complete the tree. This can happen if something suspended in
2200 - // the shell.
2201 - } else {
2202 - // Normal case. We completed the whole tree.
2203 -
2204 - // Set this to null to indicate there's no in-progress render.
2205 - workInProgressRoot = null;
2206 - workInProgressRootRenderLanes = NoLanes;
2151 + // Set this to null to indicate there's no in-progress render.
2152 + workInProgressRoot = null;
2153 + workInProgressRootRenderLanes = NoLanes;
2154
2208 - // It's safe to process the queue now that the render phase is complete.
2209 - finishQueueingConcurrentUpdates();
2210 - }
2155 + // It's safe to process the queue now that the render phase is complete.
2156 + finishQueueingConcurrentUpdates();
2157
2212 - return exitStatus;
2158 + return workInProgressRootExitStatus;
2159 }
2160
2161 // The work loop is an extremely hot path. Tell Closure not to inline it.
@@ -2255,7 +2201,9 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
2201 //
2202 // If we were previously in prerendering mode, check if we received any new
2203 // data during an interleaved event.
2258 - workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes);
2204 + if (workInProgressRootIsPrerendering) {
2205 + workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes);
2206 + }
2207 }
2208
2209 if (__DEV__) {
@@ -3805,9 +3753,6 @@ function pingSuspendedRoot(
3753 // the logic of whether or not a root suspends once it completes.
3754 // TODO: If we're rendering sync either due to Sync, Batched or expired,
3755 // we should probably never restart.
3808 - // TODO: Attach different listeners depending on whether the listener was
3809 - // attached during prerendering. Prerender pings should not interrupt
3810 - // normal renders.
3756
3757 // If we're suspended with delay, or if it's a retry, we'll always suspend
3758 // so we can always restart.
packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js
-12
@@ -420,10 +420,6 @@ describe('ReactDeferredValue', () => {
420 // The initial value suspended, so we attempt the final value, which
421 // also suspends.
422 'Suspend! [Final]',
423 -
424 - ...(gate('enableSiblingPrerendering')
425 - ? ['Suspend! [Loading...]', 'Suspend! [Final]']
426 - : []),
423 ]);
424 expect(root).toMatchRenderedOutput(null);
425
@@ -463,10 +459,6 @@ describe('ReactDeferredValue', () => {
459 // The initial value suspended, so we attempt the final value, which
460 // also suspends.
461 'Suspend! [Final]',
466 -
467 - ...(gate('enableSiblingPrerendering')
468 - ? ['Suspend! [Loading...]', 'Suspend! [Final]']
469 - : []),
462 ]);
463 expect(root).toMatchRenderedOutput(null);
464
@@ -541,10 +533,6 @@ describe('ReactDeferredValue', () => {
533 // The initial value suspended, so we attempt the final value, which
534 // also suspends.
535 'Suspend! [Final]',
544 -
545 - ...(gate('enableSiblingPrerendering')
546 - ? ['Suspend! [Loading...]', 'Suspend! [Final]']
547 - : []),
536 ]);
537 expect(root).toMatchRenderedOutput(null);
538
packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js
-71
@@ -479,75 +479,4 @@ describe('ReactSiblingPrerendering', () => {
479 assertLog([]);
480 },
481 );
482 -
483 - it(
484 - 'when a synchronous update suspends outside a boundary, the resulting' +
485 - 'prerender is concurrent',
486 - async () => {
487 - function App() {
488 - return (
489 - <>
490 - <Text text="A" />
491 - <Text text="B" />
492 - <AsyncText text="Async" />
493 - <Text text="C" />
494 - <Text text="D" />
495 - </>
496 - );
497 - }
498 -
499 - const root = ReactNoop.createRoot();
500 - // Mount the root synchronously
501 - ReactNoop.flushSync(() => root.render(<App />));
502 -
503 - // Synchronously render everything until we suspend in the shell
504 - assertLog(['A', 'B', 'Suspend! [Async]']);
505 -
506 - if (gate('enableSiblingPrerendering')) {
507 - // The rest of the siblings begin to prerender concurrently. Notice
508 - // that we don't unwind here; we pick up where we left off above.
509 - await waitFor(['C']);
510 - await waitFor(['D']);
511 - }
512 -
513 - assertLog([]);
514 - expect(root).toMatchRenderedOutput(null);
515 -
516 - await resolveText('Async');
517 - assertLog(['A', 'B', 'Async', 'C', 'D']);
518 - expect(root).toMatchRenderedOutput('ABAsyncCD');
519 - },
520 - );
521 -
522 - it('restart a suspended sync render if something suspends while prerendering the siblings', async () => {
523 - function App() {
524 - return (
525 - <>
526 - <Text text="A" />
527 - <Text text="B" />
528 - <AsyncText text="Async" />
529 - <Text text="C" />
530 - <Text text="D" />
531 - </>
532 - );
533 - }
534 -
535 - const root = ReactNoop.createRoot();
536 - // Mount the root synchronously
537 - ReactNoop.flushSync(() => root.render(<App />));
538 -
539 - // Synchronously render everything until we suspend in the shell
540 - assertLog(['A', 'B', 'Suspend! [Async]']);
541 -
542 - if (gate('enableSiblingPrerendering')) {
543 - // The rest of the siblings begin to prerender concurrently
544 - await waitFor(['C']);
545 - }
546 -
547 - // While we're prerendering, Async resolves. We should unwind and
548 - // start over, rather than continue prerendering D.
549 - await resolveText('Async');
550 - assertLog(['A', 'B', 'Async', 'C', 'D']);
551 - expect(root).toMatchRenderedOutput('ABAsyncCD');
552 - });
482 });