mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
[Flight] Reduce risk of maximum call stack exceeded when emitting async sequence (#35159)
This commit is contained in:
committed by
GitHub
parent
fb2177c153
commit
45bc3c9f04
31
packages/react-server/src/ReactFlightServer.js
vendored
31
packages/react-server/src/ReactFlightServer.js
vendored
@@ -2347,7 +2347,8 @@ function visitAsyncNodeImpl(
|
||||
// The technique for debugging the effects of uncached data on the render is to simply uncache it.
|
||||
return null;
|
||||
}
|
||||
let previousIONode = null;
|
||||
|
||||
let previousIONode: void | null | PromiseNode | IONode = null;
|
||||
// First visit anything that blocked this sequence to start in the first place.
|
||||
if (node.previous !== null) {
|
||||
previousIONode = visitAsyncNode(
|
||||
@@ -2363,12 +2364,20 @@ function visitAsyncNodeImpl(
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// `found` represents the return value of the following switch statement.
|
||||
// We can't use multiple `return` statements in the switch statement
|
||||
// since that prevents Closure compiler from inlining `visitAsyncImpl`
|
||||
// thus doubling the call stack size.
|
||||
let found: void | null | PromiseNode | IONode;
|
||||
switch (node.tag) {
|
||||
case IO_NODE: {
|
||||
return node;
|
||||
found = node;
|
||||
break;
|
||||
}
|
||||
case UNRESOLVED_PROMISE_NODE: {
|
||||
return previousIONode;
|
||||
found = previousIONode;
|
||||
break;
|
||||
}
|
||||
case PROMISE_NODE: {
|
||||
const awaited = node.awaited;
|
||||
@@ -2379,7 +2388,8 @@ function visitAsyncNodeImpl(
|
||||
if (ioNode === undefined) {
|
||||
// Undefined is used as a signal that we found a suitable aborted node and we don't have to find
|
||||
// further aborted nodes.
|
||||
return undefined;
|
||||
found = undefined;
|
||||
break;
|
||||
} else if (ioNode !== null) {
|
||||
// This Promise was blocked on I/O. That's a signal that this Promise is interesting to log.
|
||||
// We don't log it yet though. We return it to be logged by the point where it's awaited.
|
||||
@@ -2436,10 +2446,12 @@ function visitAsyncNodeImpl(
|
||||
forwardDebugInfo(request, task, debugInfo);
|
||||
}
|
||||
}
|
||||
return match;
|
||||
found = match;
|
||||
break;
|
||||
}
|
||||
case UNRESOLVED_AWAIT_NODE: {
|
||||
return previousIONode;
|
||||
found = previousIONode;
|
||||
break;
|
||||
}
|
||||
case AWAIT_NODE: {
|
||||
const awaited = node.awaited;
|
||||
@@ -2449,7 +2461,8 @@ function visitAsyncNodeImpl(
|
||||
if (ioNode === undefined) {
|
||||
// Undefined is used as a signal that we found a suitable aborted node and we don't have to find
|
||||
// further aborted nodes.
|
||||
return undefined;
|
||||
found = undefined;
|
||||
break;
|
||||
} else if (ioNode !== null) {
|
||||
const startTime: number = node.start;
|
||||
const endTime: number = node.end;
|
||||
@@ -2545,13 +2558,15 @@ function visitAsyncNodeImpl(
|
||||
forwardDebugInfo(request, task, debugInfo);
|
||||
}
|
||||
}
|
||||
return match;
|
||||
found = match;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// eslint-disable-next-line react-internal/prod-error-codes
|
||||
throw new Error('Unknown AsyncSequence tag. This is a bug in React.');
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
function emitAsyncSequence(
|
||||
|
||||
Reference in New Issue
Block a user