Skip to content

Commit 75e9afd

Browse files
committed
Revert "Check if suspensey instance resolves in immediate task (facebook#26427)"
This reverts commit 0131d0c.
1 parent 0131d0c commit 75e9afd

File tree

13 files changed

+78
-271
lines changed

13 files changed

+78
-271
lines changed

packages/react-art/src/ReactARTHostConfig.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -459,15 +459,10 @@ export function requestPostPaintCallback(callback: (time: number) => void) {
459459
// noop
460460
}
461461

462-
export function maySuspendCommit(type, props) {
462+
export function shouldSuspendCommit(type, props) {
463463
return false;
464464
}
465465

466-
export function preloadInstance(type, props) {
467-
// Return true to indicate it's already loaded
468-
return true;
469-
}
470-
471466
export function startSuspendingCommit() {}
472467

473468
export function suspendInstance(type, props) {}

packages/react-dom-bindings/src/client/ReactDOMHostConfig.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,15 +1609,10 @@ export function requestPostPaintCallback(callback: (time: number) => void) {
16091609
});
16101610
}
16111611

1612-
export function maySuspendCommit(type: Type, props: Props): boolean {
1612+
export function shouldSuspendCommit(type: Type, props: Props): boolean {
16131613
return false;
16141614
}
16151615

1616-
export function preloadInstance(type: Type, props: Props): boolean {
1617-
// Return true to indicate it's already loaded
1618-
return true;
1619-
}
1620-
16211616
export function startSuspendingCommit(): void {}
16221617

16231618
export function suspendInstance(type: Type, props: Props): void {}

packages/react-native-renderer/src/ReactFabricHostConfig.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,14 +421,10 @@ export function requestPostPaintCallback(callback: (time: number) => void) {
421421
// noop
422422
}
423423

424-
export function maySuspendCommit(type: Type, props: Props): boolean {
424+
export function shouldSuspendCommit(type: Type, props: Props): boolean {
425425
return false;
426426
}
427427

428-
export function preloadInstance(type: Type, props: Props): boolean {
429-
return true;
430-
}
431-
432428
export function startSuspendingCommit(): void {}
433429

434430
export function suspendInstance(type: Type, props: Props): void {}

packages/react-native-renderer/src/ReactNativeHostConfig.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -522,15 +522,10 @@ export function requestPostPaintCallback(callback: (time: number) => void) {
522522
// noop
523523
}
524524

525-
export function maySuspendCommit(type: Type, props: Props): boolean {
525+
export function shouldSuspendCommit(type: Type, props: Props): boolean {
526526
return false;
527527
}
528528

529-
export function preloadInstance(type: Type, props: Props): boolean {
530-
// Return true to indicate it's already loaded
531-
return true;
532-
}
533-
534529
export function startSuspendingCommit(): void {}
535530

536531
export function suspendInstance(type: Type, props: Props): void {}

packages/react-noop-renderer/src/createReactNoop.js

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
312312
if (record === undefined) {
313313
throw new Error('Could not find record for key.');
314314
}
315-
if (record.status === 'fulfilled') {
316-
// Already loaded.
317-
} else if (record.status === 'pending') {
315+
if (record.status === 'pending') {
318316
if (suspenseyCommitSubscription === null) {
319317
suspenseyCommitSubscription = {
320318
pendingCount: 1,
@@ -323,19 +321,20 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
323321
} else {
324322
suspenseyCommitSubscription.pendingCount++;
325323
}
326-
// Stash the subscription on the record. In `resolveSuspenseyThing`,
327-
// we'll use this fire the commit once all the things have loaded.
328-
if (record.subscriptions === null) {
329-
record.subscriptions = [];
330-
}
331-
record.subscriptions.push(suspenseyCommitSubscription);
332324
}
325+
// Stash the subscription on the record. In `resolveSuspenseyThing`,
326+
// we'll use this fire the commit once all the things have loaded.
327+
if (record.subscriptions === null) {
328+
record.subscriptions = [];
329+
}
330+
record.subscriptions.push(suspenseyCommitSubscription);
333331
} else {
334332
throw new Error(
335333
'Did not expect this host component to be visited when suspending ' +
336334
'the commit. Did you check the SuspendCommit flag?',
337335
);
338336
}
337+
return suspenseyCommitSubscription;
339338
}
340339

341340
function waitForCommitToBeReady():
@@ -570,42 +569,38 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
570569
callback(endTime);
571570
},
572571

573-
maySuspendCommit(type: string, props: Props): boolean {
574-
// Asks whether it's possible for this combination of type and props
575-
// to ever need to suspend. This is different from asking whether it's
576-
// currently ready because even if it's ready now, it might get purged
577-
// from the cache later.
578-
return type === 'suspensey-thing' && typeof props.src === 'string';
579-
},
580-
581-
preloadInstance(type: string, props: Props): boolean {
582-
if (type !== 'suspensey-thing' || typeof props.src !== 'string') {
583-
throw new Error('Attempted to preload unexpected instance: ' + type);
584-
}
585-
586-
// In addition to preloading an instance, this method asks whether the
587-
// instance is ready to be committed. If it's not, React may yield to the
588-
// main thread and ask again. It's possible a load event will fire in
589-
// between, in which case we can avoid showing a fallback.
590-
if (suspenseyThingCache === null) {
591-
suspenseyThingCache = new Map();
592-
}
593-
const record = suspenseyThingCache.get(props.src);
594-
if (record === undefined) {
595-
const newRecord: SuspenseyThingRecord = {
596-
status: 'pending',
597-
subscriptions: null,
598-
};
599-
suspenseyThingCache.set(props.src, newRecord);
600-
const onLoadStart = props.onLoadStart;
601-
if (typeof onLoadStart === 'function') {
602-
onLoadStart();
572+
shouldSuspendCommit(type: string, props: Props): boolean {
573+
if (type === 'suspensey-thing' && typeof props.src === 'string') {
574+
if (suspenseyThingCache === null) {
575+
suspenseyThingCache = new Map();
576+
}
577+
const record = suspenseyThingCache.get(props.src);
578+
if (record === undefined) {
579+
const newRecord: SuspenseyThingRecord = {
580+
status: 'pending',
581+
subscriptions: null,
582+
};
583+
suspenseyThingCache.set(props.src, newRecord);
584+
const onLoadStart = props.onLoadStart;
585+
if (typeof onLoadStart === 'function') {
586+
onLoadStart();
587+
}
588+
return props.src;
589+
} else {
590+
if (record.status === 'pending') {
591+
// The resource was already requested, but it hasn't finished
592+
// loading yet.
593+
return true;
594+
} else {
595+
// The resource has already loaded. If the renderer is confident that
596+
// the resource will still be cached by the time the render commits,
597+
// then it can return false, like we do here.
598+
return false;
599+
}
603600
}
604-
return false;
605-
} else {
606-
// If this is false, React will trigger a fallback, if needed.
607-
return record.status === 'fulfilled';
608601
}
602+
// Don't need to suspend.
603+
return false;
609604
},
610605

611606
startSuspendingCommit,

packages/react-reconciler/src/ReactFiberCompleteWork.js

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ import {
111111
finalizeContainerChildren,
112112
preparePortalMount,
113113
prepareScopeUpdate,
114-
maySuspendCommit,
115-
preloadInstance,
114+
shouldSuspendCommit,
116115
} from './ReactFiberHostConfig';
117116
import {
118117
getRootHostContainer,
@@ -435,6 +434,8 @@ function updateHostComponent(
435434
// Even better would be if children weren't special cased at all tho.
436435
const instance: Instance = workInProgress.stateNode;
437436

437+
suspendHostCommitIfNeeded(workInProgress, type, newProps, renderLanes);
438+
438439
const currentHostContext = getHostContext();
439440
// TODO: Experiencing an error where oldProps is null. Suggests a host
440441
// component is hitting the resume path. Figure out why. Possibly
@@ -494,6 +495,8 @@ function updateHostComponent(
494495
recyclableInstance,
495496
);
496497

498+
suspendHostCommitIfNeeded(workInProgress, type, newProps, renderLanes);
499+
497500
if (
498501
finalizeInitialChildren(newInstance, type, newProps, currentHostContext)
499502
) {
@@ -516,17 +519,17 @@ function updateHostComponent(
516519
// not created until the complete phase. For our existing use cases, host nodes
517520
// that suspend don't have children, so it doesn't matter. But that might not
518521
// always be true in the future.
519-
function preloadInstanceAndSuspendIfNeeded(
522+
function suspendHostCommitIfNeeded(
520523
workInProgress: Fiber,
521524
type: Type,
522525
props: Props,
523526
renderLanes: Lanes,
524527
) {
525528
// Ask the renderer if this instance should suspend the commit.
526-
if (!maySuspendCommit(type, props)) {
529+
if (!shouldSuspendCommit(type, props)) {
527530
// If this flag was set previously, we can remove it. The flag represents
528531
// whether this particular set of props might ever need to suspend. The
529-
// safest thing to do is for maySuspendCommit to always return true, but
532+
// safest thing to do is for shouldSuspendCommit to always return true, but
530533
// if the renderer is reasonably confident that the underlying resource
531534
// won't be evicted, it can return false as a performance optimization.
532535
workInProgress.flags &= ~SuspenseyCommit;
@@ -549,24 +552,16 @@ function preloadInstanceAndSuspendIfNeeded(
549552
// TODO: We may decide to expose a way to force a fallback even during a
550553
// sync update.
551554
if (!includesOnlyNonUrgentLanes(renderLanes)) {
552-
// This is an urgent render. Don't suspend or show a fallback. Also,
553-
// there's no need to preload, because we're going to commit this
554-
// synchronously anyway.
555-
// TODO: Could there be benefit to preloading even during a synchronous
556-
// render? The main thread will be blocked until the commit phase, but
557-
// maybe the browser would be able to start loading off thread anyway?
558-
// Likely a micro-optimization either way because typically new content
559-
// is loaded during a transition, not an urgent render.
555+
// This is an urgent render. Never suspend or trigger a fallback.
560556
} else {
561-
// Preload the instance
562-
const isReady = preloadInstance(type, props);
563-
if (!isReady) {
564-
if (shouldRemainOnPreviousScreen()) {
565-
// It's OK to suspend. Continue rendering.
566-
} else {
567-
// Trigger a fallback rather than block the render.
568-
suspendCommit();
569-
}
557+
// Need to decide whether to activate the nearest fallback or to continue
558+
// rendering and suspend right before the commit phase.
559+
if (shouldRemainOnPreviousScreen()) {
560+
// It's OK to block the commit. Don't show a fallback.
561+
} else {
562+
// We shouldn't block the commit. Activate a fallback at the nearest
563+
// Suspense boundary.
564+
suspendCommit();
570565
}
571566
}
572567
}
@@ -1059,17 +1054,6 @@ function completeWork(
10591054
);
10601055
}
10611056
bubbleProperties(workInProgress);
1062-
1063-
// This must come at the very end of the complete phase, because it might
1064-
// throw to suspend, and if the resource immediately loads, the work loop
1065-
// will resume rendering as if the work-in-progress completed. So it must
1066-
// fully complete.
1067-
preloadInstanceAndSuspendIfNeeded(
1068-
workInProgress,
1069-
workInProgress.type,
1070-
workInProgress.pendingProps,
1071-
renderLanes,
1072-
);
10731057
return null;
10741058
}
10751059
}
@@ -1208,23 +1192,14 @@ function completeWork(
12081192
}
12091193
}
12101194

1195+
suspendHostCommitIfNeeded(workInProgress, type, newProps, renderLanes);
1196+
12111197
if (workInProgress.ref !== null) {
12121198
// If there is a ref on a host node we need to schedule a callback
12131199
markRef(workInProgress);
12141200
}
12151201
}
12161202
bubbleProperties(workInProgress);
1217-
1218-
// This must come at the very end of the complete phase, because it might
1219-
// throw to suspend, and if the resource immediately loads, the work loop
1220-
// will resume rendering as if the work-in-progress completed. So it must
1221-
// fully complete.
1222-
preloadInstanceAndSuspendIfNeeded(
1223-
workInProgress,
1224-
type,
1225-
newProps,
1226-
renderLanes,
1227-
);
12281203
return null;
12291204
}
12301205
case HostText: {

packages/react-reconciler/src/ReactFiberThenable.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@ export const SuspenseException: mixed = new Error(
3131
"call the promise's `.catch` method and pass the result to `use`",
3232
);
3333

34-
export const SuspenseyCommitException: mixed = new Error(
35-
'Suspense Exception: This is not a real error, and should not leak into ' +
36-
"userspace. If you're seeing this, it's likely a bug in React.",
37-
);
38-
3934
// This is a noop thenable that we use to trigger a fallback in throwException.
4035
// TODO: It would be better to refactor throwException into multiple functions
4136
// so we can trigger a fallback directly without having to check the type. But
@@ -156,7 +151,7 @@ export function suspendCommit(): void {
156151
// noopSuspenseyCommitThenable through to throwException.
157152
// TODO: Factor the thenable check out of throwException
158153
suspendedThenable = noopSuspenseyCommitThenable;
159-
throw SuspenseyCommitException;
154+
throw SuspenseException;
160155
}
161156

162157
// This is used to track the actual thenable that suspended so it can be

0 commit comments

Comments
 (0)