From 9406162bc95f1db78169a7f5e11bc56d324b2071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 25 Jun 2025 17:28:59 -0400 Subject: [PATCH] [Flight] Emit start time before an await if one wasn't emitted already (#33646) There's a special case where if we create a new task, e.g. to serialize a promise like `
{promise}
` then that row doesn't have any start time emitted but it has a `task.time` inherited. We mostly don't need this because every other operation emits its own start time. E.g. when we started rendering a Server Component or the real start time of a real `await`. For these implied awaits we don't have a start time. Ideally it would probably be when we started the serialization, like when we called `.then()` but we can't just emit that eagerly and we can't just advance the `task.time` because that time represents the last render or previous await and we use that to cut off awaits. However for this case we don't want to cut off any inner awaits inside the node we're serializing if they happened before the `.then()`. Therefore, I just use the time of the previous operation - which is likely either the resolution of a previous promise that blocked the `
` like the promise of the Server Component that rendered it, or just the start of the Server Component if it was sync. --- packages/react-server/src/ReactFlightServer.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 8a0f517ed5..77f25f6e1b 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -2211,6 +2211,10 @@ function emitAsyncSequence( debugInfo.stack = filterStackTrace(request, parseStackTrace(stack, 1)); } } + // We don't have a start time for this await but in case there was no start time emitted + // we need to include something. TODO: We should maybe ideally track the time when we + // called .then() but without updating the task.time field since that's used for the cutoff. + advanceTaskTime(request, task, task.time); emitDebugChunk(request, task.id, debugInfo); // Mark the end time of the await. If we're aborting then we don't emit this // to signal that this never resolved inside this render. @@ -4752,6 +4756,10 @@ function forwardDebugInfoFromAbortedTask(request: Request, task: Task): void { awaited: ((node: any): ReactIOInfo), // This is deduped by this reference. env: env, }; + // We don't have a start time for this await but in case there was no start time emitted + // we need to include something. TODO: We should maybe ideally track the time when we + // called .then() but without updating the task.time field since that's used for the cutoff. + advanceTaskTime(request, task, task.time); emitDebugChunk(request, task.id, asyncInfo); } else { emitAsyncSequence(request, task, sequence, debugInfo, null, null);