Skip to content

Commit b1a9296

Browse files
committed
Revert yieldy behavior for non-use Suspense (in Flight, too)
Same as #25537 but for Flight. I was going to wait to do this later because the temporary implementation of async components uses some of the same code that non-used wakables do, but it's not so bad. I just had to inline one bit of code, which we'll remove when we unify the implementation with `use`.
1 parent 0c11baa commit b1a9296

File tree

2 files changed

+45
-33
lines changed

2 files changed

+45
-33
lines changed

packages/react-server/src/ReactFlightServer.js

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import type {
2222
ServerContextJSONValue,
2323
Wakeable,
2424
Thenable,
25+
PendingThenable,
26+
FulfilledThenable,
27+
RejectedThenable,
2528
} from 'shared/ReactTypes';
2629
import type {LazyComponent} from 'react/src/ReactLazy';
2730

@@ -64,7 +67,6 @@ import {
6467
getActiveContext,
6568
rootContextSnapshot,
6669
} from './ReactFlightNewContext';
67-
import {trackSuspendedWakeable} from './ReactFlightThenable';
6870

6971
import {
7072
REACT_ELEMENT_TYPE,
@@ -212,10 +214,44 @@ function readThenable<T>(thenable: Thenable<T>): T {
212214
}
213215

214216
function createLazyWrapperAroundWakeable(wakeable: Wakeable) {
215-
trackSuspendedWakeable(wakeable);
217+
// This is a temporary fork of the `use` implementation until we accept
218+
// promises everywhere.
219+
const thenable: Thenable<mixed> = (wakeable: any);
220+
switch (thenable.status) {
221+
case 'fulfilled':
222+
case 'rejected':
223+
break;
224+
default: {
225+
if (typeof thenable.status === 'string') {
226+
// Only instrument the thenable if the status if not defined. If
227+
// it's defined, but an unknown value, assume it's been instrumented by
228+
// some custom userspace implementation. We treat it as "pending".
229+
break;
230+
}
231+
const pendingThenable: PendingThenable<mixed> = (thenable: any);
232+
pendingThenable.status = 'pending';
233+
pendingThenable.then(
234+
fulfilledValue => {
235+
if (thenable.status === 'pending') {
236+
const fulfilledThenable: FulfilledThenable<mixed> = (thenable: any);
237+
fulfilledThenable.status = 'fulfilled';
238+
fulfilledThenable.value = fulfilledValue;
239+
}
240+
},
241+
(error: mixed) => {
242+
if (thenable.status === 'pending') {
243+
const rejectedThenable: RejectedThenable<mixed> = (thenable: any);
244+
rejectedThenable.status = 'rejected';
245+
rejectedThenable.reason = error;
246+
}
247+
},
248+
);
249+
break;
250+
}
251+
}
216252
const lazyType: LazyComponent<any, Thenable<any>> = {
217253
$$typeof: REACT_LAZY_TYPE,
218-
_payload: (wakeable: any),
254+
_payload: thenable,
219255
_init: readThenable,
220256
};
221257
return lazyType;
@@ -806,11 +842,7 @@ export function resolveModelToJSON(
806842
);
807843
const ping = newTask.ping;
808844
x.then(ping, ping);
809-
810-
const wakeable: Wakeable = x;
811-
trackSuspendedWakeable(wakeable);
812845
newTask.thenableState = getThenableStateAfterSuspending();
813-
814846
return serializeByRefID(newTask.id);
815847
} else {
816848
// Something errored. We'll still send everything we have up until this point.
@@ -1134,9 +1166,6 @@ function retryTask(request: Request, task: Task): void {
11341166
// Something suspended again, let's pick it back up later.
11351167
const ping = task.ping;
11361168
x.then(ping, ping);
1137-
1138-
const wakeable: Wakeable = x;
1139-
trackSuspendedWakeable(wakeable);
11401169
task.thenableState = getThenableStateAfterSuspending();
11411170
return;
11421171
} else {

packages/react-server/src/ReactFlightThenable.js

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
// instead of "Wakeable". Or some other more appropriate name.
1515

1616
import type {
17-
Wakeable,
1817
Thenable,
1918
PendingThenable,
2019
FulfilledThenable,
@@ -30,14 +29,12 @@ export function createThenableState(): ThenableState {
3029
return [];
3130
}
3231

33-
// TODO: Unify this with trackSuspendedThenable. It needs to support not only
34-
// `use`, but async components, too.
35-
export function trackSuspendedWakeable(wakeable: Wakeable) {
36-
// If this wakeable isn't already a thenable, turn it into one now. Then,
37-
// when we resume the work loop, we can check if its status is
38-
// still pending.
39-
// TODO: Get rid of the Wakeable type? It's superseded by UntrackedThenable.
40-
const thenable: Thenable<mixed> = (wakeable: any);
32+
export function trackUsedThenable<T>(
33+
thenableState: ThenableState,
34+
thenable: Thenable<T>,
35+
index: number,
36+
) {
37+
thenableState[index] = thenable;
4138

4239
// We use an expando to track the status and result of a thenable so that we
4340
// can synchronously unwrap the value. Think of this as an extension of the
@@ -84,20 +81,6 @@ export function trackSuspendedWakeable(wakeable: Wakeable) {
8481
}
8582
}
8683

87-
export function trackUsedThenable<T>(
88-
thenableState: ThenableState,
89-
thenable: Thenable<T>,
90-
index: number,
91-
) {
92-
// This is only a separate function from trackSuspendedWakeable for symmetry
93-
// with Fiber.
94-
// TODO: Disallow throwing a thenable directly. It must go through `use` (or
95-
// some equivalent for internal Suspense implementations). We can't do this in
96-
// Fiber yet because it's a breaking change but we can do it in Server
97-
// Components because Server Components aren't released yet.
98-
thenableState[index] = thenable;
99-
}
100-
10184
export function getPreviouslyUsedThenableAtIndex<T>(
10285
thenableState: ThenableState | null,
10386
index: number,

0 commit comments

Comments
 (0)