Skip to content

Commit 4c3a1fa

Browse files
committed
[Flight] Improve aborted hanging promise stacks
1 parent bdecc50 commit 4c3a1fa

File tree

1 file changed

+24
-5
lines changed

1 file changed

+24
-5
lines changed

packages/react-server/src/ReactFlightServer.js

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ import type {ReactElement} from 'shared/ReactElementType';
7373
import type {LazyComponent} from 'react/src/ReactLazy';
7474
import type {
7575
AsyncSequence,
76+
AwaitNode,
7677
IONode,
7778
PromiseNode,
7879
UnresolvedPromiseNode,
@@ -2254,7 +2255,7 @@ function visitAsyncNode(
22542255
node: AsyncSequence,
22552256
visited: Set<AsyncSequence | ReactDebugInfo>,
22562257
cutOff: number,
2257-
): void | null | PromiseNode | IONode {
2258+
): void | null | PromiseNode | IONode | AwaitNode {
22582259
if (visited.has(node)) {
22592260
// It's possible to visit them same node twice when it's part of both an "awaited" path
22602261
// and a "previous" path. This also gracefully handles cycles which would be a bug.
@@ -2291,8 +2292,9 @@ function visitAsyncNode(
22912292
// The technique for debugging the effects of uncached data on the render is to simply uncache it.
22922293
return previousIONode;
22932294
}
2294-
const awaited = node.awaited;
2295-
let match: void | null | PromiseNode | IONode = previousIONode;
2295+
let awaited = node.awaited;
2296+
let match: void | null | PromiseNode | IONode | AwaitNode =
2297+
previousIONode;
22962298
if (awaited !== null) {
22972299
const ioNode = visitAsyncNode(request, task, awaited, visited, cutOff);
22982300
if (ioNode === undefined) {
@@ -2324,7 +2326,23 @@ function visitAsyncNode(
23242326
// We aborted this render. If this Promise spanned the abort time it was probably the
23252327
// Promise that was aborted. This won't necessarily have I/O associated with it but
23262328
// it's a point of interest.
2329+
2330+
// If the awaited node was an await in user space, that will typically have a more
2331+
// useful stack. Try to find one, before falling back to using the promise node.
2332+
while (awaited !== null && awaited.tag === AWAIT_NODE) {
2333+
if (
2334+
awaited.stack !== null &&
2335+
hasUnfilteredFrame(request, awaited.stack)
2336+
) {
2337+
match = awaited;
2338+
break;
2339+
} else {
2340+
awaited = awaited.awaited;
2341+
}
2342+
}
2343+
23272344
if (
2345+
match === null &&
23282346
node.stack !== null &&
23292347
hasUnfilteredFrame(request, node.stack)
23302348
) {
@@ -2350,7 +2368,8 @@ function visitAsyncNode(
23502368
}
23512369
case AWAIT_NODE: {
23522370
const awaited = node.awaited;
2353-
let match: void | null | PromiseNode | IONode = previousIONode;
2371+
let match: void | null | PromiseNode | IONode | AwaitNode =
2372+
previousIONode;
23542373
if (awaited !== null) {
23552374
const ioNode = visitAsyncNode(request, task, awaited, visited, cutOff);
23562375
if (ioNode === undefined) {
@@ -4421,7 +4440,7 @@ function outlineIOInfo(request: Request, ioInfo: ReactIOInfo): void {
44214440

44224441
function serializeIONode(
44234442
request: Request,
4424-
ioNode: IONode | PromiseNode | UnresolvedPromiseNode,
4443+
ioNode: IONode | PromiseNode | UnresolvedPromiseNode | AwaitNode,
44254444
promiseRef: null | WeakRef<Promise<mixed>>,
44264445
): string {
44274446
const existingRef = request.writtenDebugObjects.get(ioNode);

0 commit comments

Comments
 (0)