Skip to content

Commit

Permalink
Schedule prerender after something suspends (#30800)
Browse files Browse the repository at this point in the history
Adds the concept of a "prerender". These special renders are spawned
whenever something suspends (and we're not already prerendering).

The purpose is to move speculative rendering work into a separate phase
that does not block the UI from updating. For example, during a
transition, if something suspends, we should not speculatively prerender
siblings that will be replaced by a fallback in the UI until *after* the
fallback has been shown to the user.

DiffTrain build for commit e10e868.
  • Loading branch information
acdlite committed Sep 4, 2024
1 parent 9625df2 commit 9e99471
Show file tree
Hide file tree
Showing 14 changed files with 1,764 additions and 1,241 deletions.
2 changes: 1 addition & 1 deletion compiled-rn/VERSION_NATIVE_FB
Original file line number Diff line number Diff line change
@@ -1 +1 @@
19.0.0-native-fb-8b4c54c0-20240904
19.0.0-native-fb-e10e8681-20240904
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<c6f7f903e1bec097563ebf3f278e6601>>
* @generated SignedSource<<c5472110548ebd348fb228d3551e271d>>
*/

"use strict";
__DEV__ &&
(function () {
function JSCompiler_object_inline_createNodeMock_1089() {
function JSCompiler_object_inline_createNodeMock_1082() {
return null;
}
function findHook(fiber, id) {
Expand Down Expand Up @@ -854,28 +854,37 @@ __DEV__ &&
var pendingLanes = root.pendingLanes;
if (0 === pendingLanes) return 0;
var nextLanes = 0,
suspendedLanes = root.suspendedLanes;
root = root.pingedLanes;
suspendedLanes = root.suspendedLanes,
pingedLanes = root.pingedLanes;
root = root.warmLanes;
var nonIdlePendingLanes = pendingLanes & 134217727;
0 !== nonIdlePendingLanes
? ((pendingLanes = nonIdlePendingLanes & ~suspendedLanes),
0 !== pendingLanes
? (nextLanes = getHighestPriorityLanes(pendingLanes))
: ((root &= nonIdlePendingLanes),
0 !== root && (nextLanes = getHighestPriorityLanes(root))))
: ((pendingLanes &= ~suspendedLanes),
0 !== pendingLanes
? (nextLanes = getHighestPriorityLanes(pendingLanes))
: 0 !== root && (nextLanes = getHighestPriorityLanes(root)));
: ((pingedLanes &= nonIdlePendingLanes),
0 !== pingedLanes
? (nextLanes = getHighestPriorityLanes(pingedLanes))
: ((pingedLanes = nonIdlePendingLanes & ~root),
0 !== pingedLanes &&
(nextLanes = getHighestPriorityLanes(pingedLanes)))))
: ((nonIdlePendingLanes = pendingLanes & ~suspendedLanes),
0 !== nonIdlePendingLanes
? (nextLanes = getHighestPriorityLanes(nonIdlePendingLanes))
: 0 !== pingedLanes
? (nextLanes = getHighestPriorityLanes(pingedLanes))
: ((pingedLanes = pendingLanes & ~root),
0 !== pingedLanes &&
(nextLanes = getHighestPriorityLanes(pingedLanes))));
return 0 === nextLanes
? 0
: 0 !== wipLanes &&
wipLanes !== nextLanes &&
0 === (wipLanes & suspendedLanes) &&
((suspendedLanes = nextLanes & -nextLanes),
(root = wipLanes & -wipLanes),
suspendedLanes >= root ||
(32 === suspendedLanes && 0 !== (root & 4194176)))
(pingedLanes = wipLanes & -wipLanes),
suspendedLanes >= pingedLanes ||
(32 === suspendedLanes && 0 !== (pingedLanes & 4194176)))
? wipLanes
: nextLanes;
}
Expand Down Expand Up @@ -954,6 +963,7 @@ __DEV__ &&
root.pendingLanes = remainingLanes;
root.suspendedLanes = 0;
root.pingedLanes = 0;
root.warmLanes = 0;
root.expiredLanes &= remainingLanes;
root.entangledLanes &= remainingLanes;
root.errorRecoveryDisabledLanes &= remainingLanes;
Expand Down Expand Up @@ -10512,7 +10522,8 @@ __DEV__ &&
markRootSuspended(
root,
workInProgressRootRenderLanes,
workInProgressDeferredLane
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings
);
markRootUpdated(root, lane);
if (
Expand Down Expand Up @@ -10553,7 +10564,8 @@ __DEV__ &&
markRootSuspended(
root,
workInProgressRootRenderLanes,
workInProgressDeferredLane
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings
)),
ensureRootIsScheduled(root),
2 !== lane ||
Expand Down Expand Up @@ -10584,7 +10596,12 @@ __DEV__ &&
var renderWasConcurrent = shouldTimeSlice;
do {
if (didTimeout === RootDidNotComplete)
markRootSuspended(root, lanes, 0);
markRootSuspended(
root,
lanes,
0,
workInProgressRootDidSkipSuspendedSiblings
);
else {
shouldTimeSlice = root.current.alternate;
if (
Expand Down Expand Up @@ -10616,7 +10633,12 @@ __DEV__ &&
}
if (didTimeout === RootFatalErrored) {
prepareFreshStack(root, 0);
markRootSuspended(root, lanes, 0);
markRootSuspended(
root,
lanes,
0,
workInProgressRootDidSkipSuspendedSiblings
);
break;
}
root.finishedWork = shouldTimeSlice;
Expand All @@ -10632,7 +10654,8 @@ __DEV__ &&
markRootSuspended(
renderWasConcurrent,
lanes,
workInProgressDeferredLane
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings
);
break a;
}
Expand Down Expand Up @@ -10667,7 +10690,8 @@ __DEV__ &&
markRootSuspended(
renderWasConcurrent,
lanes,
workInProgressDeferredLane
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings
);
if (0 !== getNextLanes(renderWasConcurrent, 0)) break a;
renderWasConcurrent.timeoutHandle = scheduleTimeout(
Expand All @@ -10679,7 +10703,8 @@ __DEV__ &&
workInProgressTransitions,
workInProgressRootDidIncludeRecursiveRenderUpdate,
lanes,
workInProgressDeferredLane
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings
),
didTimeout
);
Expand All @@ -10692,7 +10717,8 @@ __DEV__ &&
workInProgressTransitions,
workInProgressRootDidIncludeRecursiveRenderUpdate,
lanes,
workInProgressDeferredLane
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings
);
}
}
Expand Down Expand Up @@ -10794,26 +10820,31 @@ __DEV__ &&
function markRootUpdated(root, updatedLanes) {
root.pendingLanes |= updatedLanes;
268435456 !== updatedLanes &&
((root.suspendedLanes = 0), (root.pingedLanes = 0));
((root.suspendedLanes = 0),
(root.pingedLanes = 0),
(root.warmLanes = 0));
executionContext & RenderContext
? (workInProgressRootDidIncludeRecursiveRenderUpdate = !0)
: executionContext & CommitContext &&
(didIncludeCommitPhaseUpdate = !0);
throwIfInfiniteUpdateLoopDetected();
}
function markRootSuspended(root, suspendedLanes, spawnedLane) {
function markRootSuspended(
root,
suspendedLanes,
spawnedLane,
didSkipSuspendedSiblings
) {
suspendedLanes &= ~workInProgressRootPingedLanes;
suspendedLanes &= ~workInProgressRootInterleavedUpdatedLanes;
root.suspendedLanes |= suspendedLanes;
root.pingedLanes &= ~suspendedLanes;
for (
var expirationTimes = root.expirationTimes, lanes = suspendedLanes;
0 < lanes;

) {
didSkipSuspendedSiblings || (root.warmLanes |= suspendedLanes);
didSkipSuspendedSiblings = root.expirationTimes;
for (var lanes = suspendedLanes; 0 < lanes; ) {
var index = 31 - clz32(lanes),
lane = 1 << index;
expirationTimes[index] = -1;
didSkipSuspendedSiblings[index] = -1;
lanes &= ~lane;
}
0 !== spawnedLane &&
Expand Down Expand Up @@ -10843,13 +10874,18 @@ __DEV__ &&
if (exitStatus === RootFatalErrored)
return (
prepareFreshStack(root, 0),
markRootSuspended(root, lanes, 0),
markRootSuspended(root, lanes, 0, !1),
ensureRootIsScheduled(root),
null
);
if (exitStatus === RootDidNotComplete)
return (
markRootSuspended(root, lanes, workInProgressDeferredLane),
markRootSuspended(
root,
lanes,
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings
),
ensureRootIsScheduled(root),
null
);
Expand Down Expand Up @@ -10926,7 +10962,8 @@ __DEV__ &&
workInProgressRootRenderLanes = lanes;
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
workInProgressRootDidAttachPingListener = !1;
workInProgressRootDidAttachPingListener =
workInProgressRootDidSkipSuspendedSiblings = !1;
workInProgressRootExitStatus = RootInProgress;
workInProgressDeferredLane =
workInProgressRootPingedLanes =
Expand Down Expand Up @@ -11045,7 +11082,8 @@ __DEV__ &&
markRootSuspended(
workInProgressRoot,
workInProgressRootRenderLanes,
workInProgressDeferredLane
workInProgressDeferredLane,
workInProgressRootDidSkipSuspendedSiblings
);
}
function renderRootSync(root, lanes) {
Expand Down Expand Up @@ -11351,43 +11389,20 @@ __DEV__ &&
workInProgress = null;
return;
}
if (unitOfWork.flags & 32768)
a: {
root = unitOfWork;
do {
unitOfWork = unwindWork(root.alternate, root);
if (null !== unitOfWork) {
unitOfWork.flags &= 32767;
workInProgress = unitOfWork;
break a;
}
if (0 !== (root.mode & 2)) {
stopProfilerTimerIfRunningAndRecordDelta(root, !1);
unitOfWork = root.actualDuration;
for (thrownValue = root.child; null !== thrownValue; )
(unitOfWork += thrownValue.actualDuration),
(thrownValue = thrownValue.sibling);
root.actualDuration = unitOfWork;
}
root = root.return;
null !== root &&
((root.flags |= 32768),
(root.subtreeFlags = 0),
(root.deletions = null));
workInProgress = root;
} while (null !== root);
workInProgressRootExitStatus = RootDidNotComplete;
workInProgress = null;
}
else completeUnitOfWork(unitOfWork);
unitOfWork.flags & 32768
? unwindUnitOfWork(unitOfWork, !0)
: completeUnitOfWork(unitOfWork);
}
function completeUnitOfWork(unitOfWork) {
var completedWork = unitOfWork;
do {
0 !== (completedWork.flags & 32768) &&
error$jscomp$0(
"Internal React error: Expected this fiber to be complete, but it isn't. It should have been unwound. This is a bug in React."
if (0 !== (completedWork.flags & 32768)) {
unwindUnitOfWork(
completedWork,
workInProgressRootDidSkipSuspendedSiblings
);
return;
}
var current = completedWork.alternate;
unitOfWork = completedWork.return;
0 === (completedWork.mode & 2)
Expand Down Expand Up @@ -11421,6 +11436,38 @@ __DEV__ &&
workInProgressRootExitStatus === RootInProgress &&
(workInProgressRootExitStatus = RootCompleted);
}
function unwindUnitOfWork(unitOfWork, skipSiblings) {
do {
var next = unwindWork(unitOfWork.alternate, unitOfWork);
if (null !== next) {
next.flags &= 32767;
workInProgress = next;
return;
}
if (0 !== (unitOfWork.mode & 2)) {
stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, !1);
next = unitOfWork.actualDuration;
for (var child = unitOfWork.child; null !== child; )
(next += child.actualDuration), (child = child.sibling);
unitOfWork.actualDuration = next;
}
next = unitOfWork.return;
null !== next &&
((next.flags |= 32768),
(next.subtreeFlags = 0),
(next.deletions = null));
if (
!skipSiblings &&
((unitOfWork = unitOfWork.sibling), null !== unitOfWork)
) {
workInProgress = unitOfWork;
return;
}
workInProgress = unitOfWork = next;
} while (null !== unitOfWork);
workInProgressRootExitStatus = RootDidNotComplete;
workInProgress = null;
}
function commitRoot(
root,
recoverableErrors,
Expand Down Expand Up @@ -11827,6 +11874,7 @@ __DEV__ &&
var pingCache = root.pingCache;
null !== pingCache && pingCache.delete(wakeable);
root.pingedLanes |= root.suspendedLanes & pingedLanes;
root.warmLanes &= ~pingedLanes;
executionContext & RenderContext
? (workInProgressRootDidIncludeRecursiveRenderUpdate = !0)
: executionContext & CommitContext &&
Expand Down Expand Up @@ -12540,6 +12588,7 @@ __DEV__ &&
this.errorRecoveryDisabledLanes =
this.finishedLanes =
this.expiredLanes =
this.warmLanes =
this.pingedLanes =
this.suspendedLanes =
this.pendingLanes =
Expand Down Expand Up @@ -14703,6 +14752,7 @@ __DEV__ &&
SuspendedOnHydration = 8,
workInProgressSuspendedReason = NotSuspended,
workInProgressThrownValue = null,
workInProgressRootDidSkipSuspendedSiblings = !1,
workInProgressRootDidAttachPingListener = !1,
entangledRenderLanes = 0,
workInProgressRootExitStatus = RootInProgress,
Expand Down Expand Up @@ -14952,11 +15002,11 @@ __DEV__ &&
(function () {
var internals = {
bundleType: 1,
version: "19.0.0-native-fb-8b4c54c0-20240904",
version: "19.0.0-native-fb-e10e8681-20240904",
rendererPackageName: "react-test-renderer",
currentDispatcherRef: ReactSharedInternals,
findFiberByHostInstance: getInstanceFromNode,
reconcilerVersion: "19.0.0-native-fb-8b4c54c0-20240904"
reconcilerVersion: "19.0.0-native-fb-e10e8681-20240904"
};
internals.overrideHookState = overrideHookState;
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
Expand All @@ -14978,7 +15028,7 @@ __DEV__ &&
exports._Scheduler = Scheduler;
exports.act = act;
exports.create = function (element, options) {
var createNodeMock = JSCompiler_object_inline_createNodeMock_1089,
var createNodeMock = JSCompiler_object_inline_createNodeMock_1082,
isConcurrent = !1,
isStrictMode = !1;
"object" === typeof options &&
Expand Down Expand Up @@ -15101,5 +15151,5 @@ __DEV__ &&
flushSyncWorkAcrossRoots_impl(0, !0));
}
};
exports.version = "19.0.0-native-fb-8b4c54c0-20240904";
exports.version = "19.0.0-native-fb-e10e8681-20240904";
})();
Loading

0 comments on commit 9e99471

Please sign in to comment.