@samitouri / QOS-React-2 / commits / 2a911f27dd

[Flight] Send the awaited Promise to the client as additional debug information (#33592)

Stacked on #33588, #33589 and #33590. This lets us automatically show the resolved value in the UI. <img width="863" alt="Screenshot 2025-06-22 at 12 54 41 AM" src="https://github.com/user-attachments/assets/a66d1d5e-0513-4767-910c-5c7169fc2df4" /> We can also show rejected I/O that may or may not have been handled with the error message. <img width="838" alt="Screenshot 2025-06-22 at 12 55 06 AM" src="https://github.com/user-attachments/assets/e0a8b6ae-08ba-46d8-8cc5-efb60956a1d1" /> To get this working we need to keep the Promise around for longer so that we can access it once we want to emit an async sequence. I do this by storing the WeakRefs but to ensure that the Promise doesn't get garbage collected, I keep a WeakMap of Promise to the Promise that it depended on. This lets the VM still clean up any Promise chains that have leaves that are cleaned up. So this makes Promises live until the last Promise downstream is done. At that point we can go back up the chain to read the values out of them. Additionally, to get the best possible value we don't want to get a Promise that's used by internals of a third-party function. We want the value that the first party gets to observe. To do this I had to change the logic for which "await" to use, to be the one that is the first await that happened in user space. It's not enough that the await has any first party at all on the stack - it has to be the very first frame. This is a little sketchy because it relies on the `.then()` call or `await` call not having any third party wrappers. But it gives the best object since it hides all the internals. For example when you call `fetch()` we now log that actual `Response` object.

Sebastian Markbåge committed Jun 23, 2025 at 10:12 UTC 2a911f27dd99c46778c27ba004f9d8fe898efd21
9 files changed +791 -296
fixtures/flight/src/App.js
+12 -1
@@ -33,12 +33,22 @@ function Foo({children}) {
33 return <div>{children}</div>;
34 }
35
36 +async function delayedError(text, ms) {
37 + return new Promise((_, reject) =>
38 + setTimeout(() => reject(new Error(text)), ms)
39 + );
40 +}
41 +
42 async function delay(text, ms) {
43 return new Promise(resolve => setTimeout(() => resolve(text), ms));
44 }
45
46 async function delayTwice() {
41 - await delay('', 20);
47 + try {
48 + await delayedError('Delayed exception', 20);
49 + } catch (x) {
50 + // Ignored
51 + }
52 await delay('', 10);
53 }
54
@@ -113,6 +123,7 @@ async function ServerComponent({noCache}) {
123 export default async function App({prerender, noCache}) {
124 const res = await fetch('http://localhost:3001/todos');
125 const todos = await res.json();
126 + console.log(res);
127
128 const dedupedChild = <ServerComponent noCache={noCache} />;
129 const message = getServerState();
packages/react-client/src/ReactFlightClient.js
+77 -13
@@ -79,7 +79,9 @@ import {
79 logDedupedComponentRender,
80 logComponentErrored,
81 logIOInfo,
82 + logIOInfoErrored,
83 logComponentAwait,
84 + logComponentAwaitErrored,
85 } from './ReactFlightPerformanceTrack';
86
87 import {
@@ -96,6 +98,8 @@ import {getOwnerStackByComponentInfoInDev} from 'shared/ReactComponentInfoStack'
98
99 import {injectInternals} from './ReactFlightClientDevToolsHook';
100
101 +import {OMITTED_PROP_ERROR} from './ReactFlightPropertyAccess';
102 +
103 import ReactVersion from 'shared/ReactVersion';
104
105 import isArray from 'shared/isArray';
@@ -1684,11 +1688,7 @@ function parseModelString(
1688 Object.defineProperty(parentObject, key, {
1689 get: function () {
1690 // TODO: We should ideally throw here to indicate a difference.
1687 - return (
1688 - 'This object has been omitted by React in the console log ' +
1689 - 'to avoid sending too much data from the server. Try logging smaller ' +
1690 - 'or more specific objects.'
1691 - );
1691 + return OMITTED_PROP_ERROR;
1692 },
1693 enumerable: true,
1694 configurable: false,
@@ -2909,7 +2909,29 @@ function initializeIOInfo(response: Response, ioInfo: ReactIOInfo): void {
2909 // $FlowFixMe[cannot-write]
2910 ioInfo.end += response._timeOrigin;
2911
2912 - logIOInfo(ioInfo, response._rootEnvironmentName);
2912 + const env = response._rootEnvironmentName;
2913 + const promise = ioInfo.value;
2914 + if (promise) {
2915 + const thenable: Thenable<mixed> = (promise: any);
2916 + switch (thenable.status) {
2917 + case INITIALIZED:
2918 + logIOInfo(ioInfo, env, thenable.value);
2919 + break;
2920 + case ERRORED:
2921 + logIOInfoErrored(ioInfo, env, thenable.reason);
2922 + break;
2923 + default:
2924 + // If we haven't resolved the Promise yet, wait to log until have so we can include
2925 + // its data in the log.
2926 + promise.then(
2927 + logIOInfo.bind(null, ioInfo, env),
2928 + logIOInfoErrored.bind(null, ioInfo, env),
2929 + );
2930 + break;
2931 + }
2932 + } else {
2933 + logIOInfo(ioInfo, env, undefined);
2934 + }
2935 }
2936
2937 function resolveIOInfo(
@@ -3193,13 +3215,55 @@ function flushComponentPerformance(
3215 }
3216 // $FlowFixMe: Refined.
3217 const asyncInfo: ReactAsyncInfo = candidateInfo;
3196 - logComponentAwait(
3197 - asyncInfo,
3198 - trackIdx,
3199 - time,
3200 - endTime,
3201 - response._rootEnvironmentName,
3202 - );
3218 + const env = response._rootEnvironmentName;
3219 + const promise = asyncInfo.awaited.value;
3220 + if (promise) {
3221 + const thenable: Thenable<mixed> = (promise: any);
3222 + switch (thenable.status) {
3223 + case INITIALIZED:
3224 + logComponentAwait(
3225 + asyncInfo,
3226 + trackIdx,
3227 + time,
3228 + endTime,
3229 + env,
3230 + thenable.value,
3231 + );
3232 + break;
3233 + case ERRORED:
3234 + logComponentAwaitErrored(
3235 + asyncInfo,
3236 + trackIdx,
3237 + time,
3238 + endTime,
3239 + env,
3240 + thenable.reason,
3241 + );
3242 + break;
3243 + default:
3244 + // We assume that we should have received the data by now since this is logged at the
3245 + // end of the response stream. This is more sensitive to ordering so we don't wait
3246 + // to log it.
3247 + logComponentAwait(
3248 + asyncInfo,
3249 + trackIdx,
3250 + time,
3251 + endTime,
3252 + env,
3253 + undefined,
3254 + );
3255 + break;
3256 + }
3257 + } else {
3258 + logComponentAwait(
3259 + asyncInfo,
3260 + trackIdx,
3261 + time,
3262 + endTime,
3263 + env,
3264 + undefined,
3265 + );
3266 + }
3267 }
3268 }
3269 }
packages/react-client/src/ReactFlightPerformanceTrack.js
+279 -26
@@ -17,14 +17,143 @@ import type {
17
18 import {enableProfilerTimer} from 'shared/ReactFeatureFlags';
19
20 +import {OMITTED_PROP_ERROR} from './ReactFlightPropertyAccess';
21 +
22 +import hasOwnProperty from 'shared/hasOwnProperty';
23 +import isArray from 'shared/isArray';
24 +
25 const supportsUserTiming =
26 enableProfilerTimer &&
27 typeof console !== 'undefined' &&
23 - typeof console.timeStamp === 'function';
28 + typeof console.timeStamp === 'function' &&
29 + typeof performance !== 'undefined' &&
30 + // $FlowFixMe[method-unbinding]
31 + typeof performance.measure === 'function';
32
33 const IO_TRACK = 'Server Requests ⚛';
34 const COMPONENTS_TRACK = 'Server Components ⚛';
35
36 +const EMPTY_ARRAY = 0;
37 +const COMPLEX_ARRAY = 1;
38 +const PRIMITIVE_ARRAY = 2; // Primitive values only
39 +const ENTRIES_ARRAY = 3; // Tuple arrays of string and value (like Headers, Map, etc)
40 +function getArrayKind(array: Object): 0 | 1 | 2 | 3 {
41 + let kind = EMPTY_ARRAY;
42 + for (let i = 0; i < array.length; i++) {
43 + const value = array[i];
44 + if (typeof value === 'object' && value !== null) {
45 + if (
46 + isArray(value) &&
47 + value.length === 2 &&
48 + typeof value[0] === 'string'
49 + ) {
50 + // Key value tuple
51 + if (kind !== EMPTY_ARRAY && kind !== ENTRIES_ARRAY) {
52 + return COMPLEX_ARRAY;
53 + }
54 + kind = ENTRIES_ARRAY;
55 + } else {
56 + return COMPLEX_ARRAY;
57 + }
58 + } else if (typeof value === 'function') {
59 + return COMPLEX_ARRAY;
60 + } else if (typeof value === 'string' && value.length > 50) {
61 + return COMPLEX_ARRAY;
62 + } else if (kind !== EMPTY_ARRAY && kind !== PRIMITIVE_ARRAY) {
63 + return COMPLEX_ARRAY;
64 + } else {
65 + kind = PRIMITIVE_ARRAY;
66 + }
67 + }
68 + return kind;
69 +}
70 +
71 +function addObjectToProperties(
72 + object: Object,
73 + properties: Array<[string, string]>,
74 + indent: number,
75 +): void {
76 + for (const key in object) {
77 + if (hasOwnProperty.call(object, key) && key[0] !== '_') {
78 + const value = object[key];
79 + addValueToProperties(key, value, properties, indent);
80 + }
81 + }
82 +}
83 +
84 +function addValueToProperties(
85 + propertyName: string,
86 + value: mixed,
87 + properties: Array<[string, string]>,
88 + indent: number,
89 +): void {
90 + let desc;
91 + switch (typeof value) {
92 + case 'object':
93 + if (value === null) {
94 + desc = 'null';
95 + break;
96 + } else {
97 + // $FlowFixMe[method-unbinding]
98 + const objectToString = Object.prototype.toString.call(value);
99 + let objectName = objectToString.slice(8, objectToString.length - 1);
100 + if (objectName === 'Array') {
101 + const array: Array<any> = (value: any);
102 + const kind = getArrayKind(array);
103 + if (kind === PRIMITIVE_ARRAY || kind === EMPTY_ARRAY) {
104 + desc = JSON.stringify(array);
105 + break;
106 + } else if (kind === ENTRIES_ARRAY) {
107 + properties.push(['\xa0\xa0'.repeat(indent) + propertyName, '']);
108 + for (let i = 0; i < array.length; i++) {
109 + const entry = array[i];
110 + addValueToProperties(entry[0], entry[1], properties, indent + 1);
111 + }
112 + return;
113 + }
114 + }
115 + if (objectName === 'Object') {
116 + const proto: any = Object.getPrototypeOf(value);
117 + if (proto && typeof proto.constructor === 'function') {
118 + objectName = proto.constructor.name;
119 + }
120 + }
121 + properties.push([
122 + '\xa0\xa0'.repeat(indent) + propertyName,
123 + objectName === 'Object' ? '' : objectName,
124 + ]);
125 + if (indent < 3) {
126 + addObjectToProperties(value, properties, indent + 1);
127 + }
128 + return;
129 + }
130 + case 'function':
131 + if (value.name === '') {
132 + desc = '() => {}';
133 + } else {
134 + desc = value.name + '() {}';
135 + }
136 + break;
137 + case 'string':
138 + if (value === OMITTED_PROP_ERROR) {
139 + desc = '...';
140 + } else {
141 + desc = JSON.stringify(value);
142 + }
143 + break;
144 + case 'undefined':
145 + desc = 'undefined';
146 + break;
147 + case 'boolean':
148 + desc = value ? 'true' : 'false';
149 + break;
150 + default:
151 + // eslint-disable-next-line react-internal/safe-string-coercion
152 + desc = String(value);
153 + }
154 + properties.push(['\xa0\xa0'.repeat(indent) + propertyName, desc]);
155 +}
156 +
157 export function markAllTracksInOrder() {
158 if (supportsUserTiming) {
159 // Ensure we create the Server Component track groups earlier than the Client Scheduler
@@ -133,12 +262,7 @@ export function logComponentErrored(
262 const isPrimaryEnv = env === rootEnv;
263 const entryName =
264 isPrimaryEnv || env === undefined ? name : name + ' [' + env + ']';
136 - if (
137 - __DEV__ &&
138 - typeof performance !== 'undefined' &&
139 - // $FlowFixMe[method-unbinding]
140 - typeof performance.measure === 'function'
141 - ) {
265 + if (__DEV__) {
266 const message =
267 typeof error === 'object' &&
268 error !== null &&
@@ -228,12 +352,68 @@ function getIOColor(
352 }
353 }
354
355 +export function logComponentAwaitErrored(
356 + asyncInfo: ReactAsyncInfo,
357 + trackIdx: number,
358 + startTime: number,
359 + endTime: number,
360 + rootEnv: string,
361 + error: mixed,
362 +): void {
363 + if (supportsUserTiming && endTime > 0) {
364 + const env = asyncInfo.env;
365 + const name = asyncInfo.awaited.name;
366 + const isPrimaryEnv = env === rootEnv;
367 + const entryName =
368 + 'await ' +
369 + (isPrimaryEnv || env === undefined ? name : name + ' [' + env + ']');
370 + const debugTask = asyncInfo.debugTask;
371 + if (__DEV__ && debugTask) {
372 + const message =
373 + typeof error === 'object' &&
374 + error !== null &&
375 + typeof error.message === 'string'
376 + ? // eslint-disable-next-line react-internal/safe-string-coercion
377 + String(error.message)
378 + : // eslint-disable-next-line react-internal/safe-string-coercion
379 + String(error);
380 + const properties = [['Rejected', message]];
381 + debugTask.run(
382 + // $FlowFixMe[method-unbinding]
383 + performance.measure.bind(performance, entryName, {
384 + start: startTime < 0 ? 0 : startTime,
385 + end: endTime,
386 + detail: {
387 + devtools: {
388 + color: 'error',
389 + track: trackNames[trackIdx],
390 + trackGroup: COMPONENTS_TRACK,
391 + properties,
392 + tooltipText: entryName + ' Rejected',
393 + },
394 + },
395 + }),
396 + );
397 + } else {
398 + console.timeStamp(
399 + entryName,
400 + startTime < 0 ? 0 : startTime,
401 + endTime,
402 + trackNames[trackIdx],
403 + COMPONENTS_TRACK,
404 + 'error',
405 + );
406 + }
407 + }
408 +}
409 +
410 export function logComponentAwait(
411 asyncInfo: ReactAsyncInfo,
412 trackIdx: number,
413 startTime: number,
414 endTime: number,
415 rootEnv: string,
416 + value: mixed,
417 ): void {
418 if (supportsUserTiming && endTime > 0) {
419 const env = asyncInfo.env;
@@ -245,17 +425,26 @@ export function logComponentAwait(
425 (isPrimaryEnv || env === undefined ? name : name + ' [' + env + ']');
426 const debugTask = asyncInfo.debugTask;
427 if (__DEV__ && debugTask) {
428 + const properties: Array<[string, string]> = [];
429 + if (typeof value === 'object' && value !== null) {
430 + addObjectToProperties(value, properties, 0);
431 + } else if (value !== undefined) {
432 + addValueToProperties('Resolved', value, properties, 0);
433 + }
434 debugTask.run(
435 // $FlowFixMe[method-unbinding]
250 - console.timeStamp.bind(
251 - console,
252 - entryName,
253 - startTime < 0 ? 0 : startTime,
254 - endTime,
255 - trackNames[trackIdx],
256 - COMPONENTS_TRACK,
257 - color,
258 - ),
436 + performance.measure.bind(performance, entryName, {
437 + start: startTime < 0 ? 0 : startTime,
438 + end: endTime,
439 + detail: {
440 + devtools: {
441 + color: color,
442 + track: trackNames[trackIdx],
443 + trackGroup: COMPONENTS_TRACK,
444 + properties,
445 + },
446 + },
447 + }),
448 );
449 } else {
450 console.timeStamp(
@@ -270,7 +459,63 @@ export function logComponentAwait(
459 }
460 }
461
273 -export function logIOInfo(ioInfo: ReactIOInfo, rootEnv: string): void {
462 +export function logIOInfoErrored(
463 + ioInfo: ReactIOInfo,
464 + rootEnv: string,
465 + error: mixed,
466 +): void {
467 + const startTime = ioInfo.start;
468 + const endTime = ioInfo.end;
469 + if (supportsUserTiming && endTime >= 0) {
470 + const name = ioInfo.name;
471 + const env = ioInfo.env;
472 + const isPrimaryEnv = env === rootEnv;
473 + const entryName =
474 + isPrimaryEnv || env === undefined ? name : name + ' [' + env + ']';
475 + const debugTask = ioInfo.debugTask;
476 + if (__DEV__ && debugTask) {
477 + const message =
478 + typeof error === 'object' &&
479 + error !== null &&
480 + typeof error.message === 'string'
481 + ? // eslint-disable-next-line react-internal/safe-string-coercion
482 + String(error.message)
483 + : // eslint-disable-next-line react-internal/safe-string-coercion
484 + String(error);
485 + const properties = [['Rejected', message]];
486 + debugTask.run(
487 + // $FlowFixMe[method-unbinding]
488 + performance.measure.bind(performance, entryName, {
489 + start: startTime < 0 ? 0 : startTime,
490 + end: endTime,
491 + detail: {
492 + devtools: {
493 + color: 'error',
494 + track: IO_TRACK,
495 + properties,
496 + tooltipText: entryName + ' Rejected',
497 + },
498 + },
499 + }),
500 + );
501 + } else {
502 + console.timeStamp(
503 + entryName,
504 + startTime < 0 ? 0 : startTime,
505 + endTime,
506 + IO_TRACK,
507 + undefined,
508 + 'error',
509 + );
510 + }
511 + }
512 +}
513 +
514 +export function logIOInfo(
515 + ioInfo: ReactIOInfo,
516 + rootEnv: string,
517 + value: mixed,
518 +): void {
519 const startTime = ioInfo.start;
520 const endTime = ioInfo.end;
521 if (supportsUserTiming && endTime >= 0) {
@@ -282,17 +527,25 @@ export function logIOInfo(ioInfo: ReactIOInfo, rootEnv: string): void {
527 const debugTask = ioInfo.debugTask;
528 const color = getIOColor(name);
529 if (__DEV__ && debugTask) {
530 + const properties: Array<[string, string]> = [];
531 + if (typeof value === 'object' && value !== null) {
532 + addObjectToProperties(value, properties, 0);
533 + } else if (value !== undefined) {
534 + addValueToProperties('Resolved', value, properties, 0);
535 + }
536 debugTask.run(
537 // $FlowFixMe[method-unbinding]
287 - console.timeStamp.bind(
288 - console,
289 - entryName,
290 - startTime < 0 ? 0 : startTime,
291 - endTime,
292 - IO_TRACK,
293 - undefined,
294 - color,
295 - ),
538 + performance.measure.bind(performance, entryName, {
539 + start: startTime < 0 ? 0 : startTime,
540 + end: endTime,
541 + detail: {
542 + devtools: {
543 + color: color,
544 + track: IO_TRACK,
545 + properties,
546 + },
547 + },
548 + }),
549 );
550 } else {
551 console.timeStamp(
packages/react-client/src/ReactFlightPropertyAccess.js new
+13
@@ -0,0 +1,13 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export const OMITTED_PROP_ERROR =
11 + 'This object has been omitted by React in the console log ' +
12 + 'to avoid sending too much data from the server. Try logging smaller ' +
13 + 'or more specific objects.';
packages/react-server/src/ReactFlightAsyncSequence.js
+5 -5
@@ -27,9 +27,9 @@ export type IONode = {
27 tag: 0,
28 owner: null | ReactComponentInfo,
29 stack: ReactStackTrace, // callsite that spawned the I/O
30 - debugInfo: null, // not used on I/O
30 start: number, // start time when the first part of the I/O sequence started
31 end: number, // we typically don't use this. only when there's no promise intermediate.
32 + promise: null, // not used on I/O
33 awaited: null, // I/O is only blocked on external.
34 previous: null | AwaitNode | UnresolvedAwaitNode, // the preceeding await that spawned this new work
35 };
@@ -37,10 +37,10 @@ export type IONode = {
37 export type PromiseNode = {
38 tag: 1,
39 owner: null | ReactComponentInfo,
40 - debugInfo: null | ReactDebugInfo, // forwarded debugInfo from the Promise
40 stack: ReactStackTrace, // callsite that created the Promise
41 start: number, // start time when the Promise was created
42 end: number, // end time when the Promise was resolved.
43 + promise: WeakRef<PromiseWithDebugInfo>, // a reference to this Promise if still referenced
44 awaited: null | AsyncSequence, // the thing that ended up resolving this promise
45 previous: null | AsyncSequence, // represents what the last return of an async function depended on before returning
46 };
@@ -48,10 +48,10 @@ export type PromiseNode = {
48 export type AwaitNode = {
49 tag: 2,
50 owner: null | ReactComponentInfo,
51 - debugInfo: null | ReactDebugInfo, // forwarded debugInfo from the Promise
51 stack: ReactStackTrace, // callsite that awaited (using await, .then(), Promise.all(), ...)
52 start: number, // when we started blocking. This might be later than the I/O started.
53 end: number, // when we unblocked. This might be later than the I/O resolved if there's CPU time.
54 + promise: WeakRef<PromiseWithDebugInfo>, // a reference to this Promise if still referenced
55 awaited: null | AsyncSequence, // the promise we were waiting on
56 previous: null | AsyncSequence, // the sequence that was blocking us from awaiting in the first place
57 };
@@ -59,10 +59,10 @@ export type AwaitNode = {
59 export type UnresolvedPromiseNode = {
60 tag: 3,
61 owner: null | ReactComponentInfo,
62 - debugInfo: WeakRef<PromiseWithDebugInfo>, // holds onto the Promise until we can extract debugInfo when it resolves
62 stack: ReactStackTrace, // callsite that created the Promise
63 start: number, // start time when the Promise was created
64 end: -1.1, // set when we resolve.
65 + promise: WeakRef<PromiseWithDebugInfo>, // a reference to this Promise if still referenced
66 awaited: null | AsyncSequence, // the thing that ended up resolving this promise
67 previous: null, // where we created the promise is not interesting since creating it doesn't mean waiting.
68 };
@@ -70,10 +70,10 @@ export type UnresolvedPromiseNode = {
70 export type UnresolvedAwaitNode = {
71 tag: 4,
72 owner: null | ReactComponentInfo,
73 - debugInfo: WeakRef<PromiseWithDebugInfo>, // holds onto the Promise until we can extract debugInfo when it resolves
73 stack: ReactStackTrace, // callsite that awaited (using await, .then(), Promise.all(), ...)
74 start: number, // when we started blocking. This might be later than the I/O started.
75 end: -1.1, // set when we resolve.
76 + promise: WeakRef<PromiseWithDebugInfo>, // a reference to this Promise if still referenced
77 awaited: null | AsyncSequence, // the promise we were waiting on
78 previous: null | AsyncSequence, // the sequence that was blocking us from awaiting in the first place
79 };
packages/react-server/src/ReactFlightServer.js
+50 -13
@@ -2053,10 +2053,13 @@ function visitAsyncNode(
2053 }
2054 // We need to forward after we visit awaited nodes because what ever I/O we requested that's
2055 // the thing that generated this node and its virtual children.
2056 - const debugInfo = node.debugInfo;
2057 - if (debugInfo !== null && !visited.has(debugInfo)) {
2058 - visited.add(debugInfo);
2059 - forwardDebugInfo(request, task, debugInfo);
2056 + const promise = node.promise.deref();
2057 + if (promise !== undefined) {
2058 + const debugInfo = promise._debugInfo;
2059 + if (debugInfo != null && !visited.has(debugInfo)) {
2060 + visited.add(debugInfo);
2061 + forwardDebugInfo(request, task, debugInfo);
2062 + }
2063 }
2064 return match;
2065 }
@@ -2084,14 +2087,32 @@ function visitAsyncNode(
2087 // just part of a previous component's rendering.
2088 match = ioNode;
2089 } else {
2087 - const stack = filterStackTrace(request, node.stack);
2088 - if (stack.length === 0) {
2090 + let isAwaitInUserspace = false;
2091 + const fullStack = node.stack;
2092 + if (fullStack.length > 0) {
2093 + // Check if the very first stack frame that awaited this Promise was in user space.
2094 + // TODO: This doesn't take into account wrapper functions such as our fake .then()
2095 + // in FlightClient which will always be considered third party awaits if you call
2096 + // .then directly.
2097 + const filterStackFrame = request.filterStackFrame;
2098 + const callsite = fullStack[0];
2099 + const functionName = callsite[0];
2100 + const url = devirtualizeURL(callsite[1]);
2101 + isAwaitInUserspace = filterStackFrame(url, functionName);
2102 + }
2103 + if (!isAwaitInUserspace) {
2104 // If this await was fully filtered out, then it was inside third party code
2105 // such as in an external library. We return the I/O node and try another await.
2106 match = ioNode;
2107 } else {
2108 + // We found a user space await.
2109 +
2110 // Outline the IO node.
2094 - serializeIONode(request, ioNode);
2111 + // The ioNode is where the I/O was initiated, but after that it could have been
2112 + // processed through various awaits in the internals of the third party code.
2113 + // Therefore we don't use the inner most Promise as the conceptual value but the
2114 + // Promise that was ultimately awaited by the user space await.
2115 + serializeIONode(request, ioNode, awaited.promise);
2116
2117 // We log the environment at the time when the last promise pigned ping which may
2118 // be later than what the environment was when we actually started awaiting.
@@ -2103,7 +2124,7 @@ function visitAsyncNode(
2124 awaited: ((ioNode: any): ReactIOInfo), // This is deduped by this reference.
2125 env: env,
2126 owner: node.owner,
2106 - stack: stack,
2127 + stack: filterStackTrace(request, node.stack),
2128 });
2129 markOperationEndTime(request, task, endTime);
2130 }
@@ -2112,10 +2133,13 @@ function visitAsyncNode(
2133 }
2134 // We need to forward after we visit awaited nodes because what ever I/O we requested that's
2135 // the thing that generated this node and its virtual children.
2115 - const debugInfo = node.debugInfo;
2116 - if (debugInfo !== null && !visited.has(debugInfo)) {
2117 - visited.add(debugInfo);
2118 - forwardDebugInfo(request, task, debugInfo);
2136 + const promise = node.promise.deref();
2137 + if (promise !== undefined) {
2138 + const debugInfo = promise._debugInfo;
2139 + if (debugInfo != null && !visited.has(debugInfo)) {
2140 + visited.add(debugInfo);
2141 + forwardDebugInfo(request, task, debugInfo);
2142 + }
2143 }
2144 return match;
2145 }
@@ -2141,7 +2165,7 @@ function emitAsyncSequence(
2165 const awaitedNode = visitAsyncNode(request, task, node, visited, task.time);
2166 if (awaitedNode !== null) {
2167 // Nothing in user space (unfiltered stack) awaited this.
2144 - serializeIONode(request, awaitedNode);
2168 + serializeIONode(request, awaitedNode, awaitedNode.promise);
2169 request.pendingChunks++;
2170 // We log the environment at the time when we ping which may be later than what the
2171 // environment was when we actually started awaiting.
@@ -3726,6 +3750,7 @@ function emitIOInfoChunk(
3750 name: string,
3751 start: number,
3752 end: number,
3753 + value: ?Promise<mixed>,
3754 env: ?string,
3755 owner: ?ReactComponentInfo,
3756 stack: ?ReactStackTrace,
@@ -3750,6 +3775,10 @@ function emitIOInfoChunk(
3775 start: relativeStartTimestamp,
3776 end: relativeEndTimestamp,
3777 };
3778 + if (value !== undefined) {
3779 + // $FlowFixMe[cannot-write]
3780 + debugIOInfo.value = value;
3781 + }
3782 if (env != null) {
3783 // $FlowFixMe[cannot-write]
3784 debugIOInfo.env = env;
@@ -3797,6 +3826,7 @@ function outlineIOInfo(request: Request, ioInfo: ReactIOInfo): void {
3826 ioInfo.name,
3827 ioInfo.start,
3828 ioInfo.end,
3829 + ioInfo.value,
3830 ioInfo.env,
3831 owner,
3832 debugStack,
@@ -3807,6 +3837,7 @@ function outlineIOInfo(request: Request, ioInfo: ReactIOInfo): void {
3837 function serializeIONode(
3838 request: Request,
3839 ioNode: IONode | PromiseNode,
3840 + promiseRef: null | WeakRef<Promise<mixed>>,
3841 ): string {
3842 const existingRef = request.writtenDebugObjects.get(ioNode);
3843 if (existingRef !== undefined) {
@@ -3834,6 +3865,11 @@ function serializeIONode(
3865 outlineComponentInfo(request, owner);
3866 }
3867
3868 + let value: void | Promise<mixed> = undefined;
3869 + if (promiseRef !== null) {
3870 + value = promiseRef.deref();
3871 + }
3872 +
3873 // We log the environment at the time when we serialize the I/O node.
3874 // The environment name may have changed from when the I/O was actually started.
3875 const env = (0, request.environmentName)();
@@ -3846,6 +3882,7 @@ function serializeIONode(
3882 name,
3883 ioNode.start,
3884 ioNode.end,
3885 + value,
3886 env,
3887 owner,
3888 stack,
packages/react-server/src/ReactFlightServerConfigDebugNode.js
+41 -14
@@ -34,6 +34,23 @@ const getAsyncId = AsyncResource.prototype.asyncId;
34 const pendingOperations: Map<number, AsyncSequence> =
35 __DEV__ && enableAsyncDebugInfo ? new Map() : (null: any);
36
37 +// This is a weird one. This map, keeps a dependent Promise alive if the child Promise is still alive.
38 +// A PromiseNode/AwaitNode cannot hold a strong reference to its own Promise because then it'll never get
39 +// GC:ed. We only need it if a dependent AwaitNode points to it. We could put a reference in the Node
40 +// but that would require a GC pass between every Node that gets destroyed. I.e. the root gets destroy()
41 +// called on it and then that release it from the pendingOperations map which allows the next one to GC
42 +// and so on. By putting this relationship in a WeakMap this could be done as a single pass in the VM.
43 +// We don't actually ever have to read from this map since we have WeakRef reference to these Promises
44 +// if they're still alive. It's also optional information so we could just expose only if GC didn't run.
45 +const awaitedPromise: WeakMap<Promise<any>, Promise<any>> = __DEV__ &&
46 +enableAsyncDebugInfo
47 + ? new WeakMap()
48 + : (null: any);
49 +const previousPromise: WeakMap<Promise<any>, Promise<any>> = __DEV__ &&
50 +enableAsyncDebugInfo
51 + ? new WeakMap()
52 + : (null: any);
53 +
54 // Keep the last resolved await as a workaround for async functions missing data.
55 let lastRanAwait: null | AwaitNode = null;
56
@@ -45,12 +62,6 @@ function resolvePromiseOrAwaitNode(
62 resolvedNode.tag = ((unresolvedNode.tag === UNRESOLVED_PROMISE_NODE
63 ? PROMISE_NODE
64 : AWAIT_NODE): any);
48 - // The Promise can be garbage collected after this so we should extract debugInfo first.
49 - const promise = unresolvedNode.debugInfo.deref();
50 - resolvedNode.debugInfo =
51 - promise === undefined || promise._debugInfo === undefined
52 - ? null
53 - : promise._debugInfo;
65 resolvedNode.end = endTime;
66 return resolvedNode;
67 }
@@ -72,6 +83,14 @@ export function initAsyncDebugInfo(): void {
83 const trigger = pendingOperations.get(triggerAsyncId);
84 let node: AsyncSequence;
85 if (type === 'PROMISE') {
86 + if (trigger !== undefined && trigger.promise !== null) {
87 + const triggerPromise = trigger.promise.deref();
88 + if (triggerPromise !== undefined) {
89 + // Keep the awaited Promise alive as long as the child is alive so we can
90 + // trace its value at the end.
91 + awaitedPromise.set(resource, triggerPromise);
92 + }
93 + }
94 const currentAsyncId = executionAsyncId();
95 if (currentAsyncId !== triggerAsyncId) {
96 // When you call .then() on a native Promise, or await/Promise.all() a thenable,
@@ -81,15 +100,23 @@ export function initAsyncDebugInfo(): void {
100 return;
101 }
102 const current = pendingOperations.get(currentAsyncId);
103 + if (current !== undefined && current.promise !== null) {
104 + const currentPromise = current.promise.deref();
105 + if (currentPromise !== undefined) {
106 + // Keep the previous Promise alive as long as the child is alive so we can
107 + // trace its value at the end.
108 + previousPromise.set(resource, currentPromise);
109 + }
110 + }
111 // If the thing we're waiting on is another Await we still track that sequence
112 // so that we can later pick the best stack trace in user space.
113 node = ({
114 tag: UNRESOLVED_AWAIT_NODE,
115 owner: resolveOwner(),
89 - debugInfo: new WeakRef((resource: Promise<any>)),
90 - stack: parseStackTrace(new Error(), 1),
116 + stack: parseStackTrace(new Error(), 5),
117 start: performance.now(),
118 end: -1.1, // set when resolved.
119 + promise: new WeakRef((resource: Promise<any>)),
120 awaited: trigger, // The thing we're awaiting on. Might get overrriden when we resolve.
121 previous: current === undefined ? null : current, // The path that led us here.
122 }: UnresolvedAwaitNode);
@@ -97,10 +124,10 @@ export function initAsyncDebugInfo(): void {
124 node = ({
125 tag: UNRESOLVED_PROMISE_NODE,
126 owner: resolveOwner(),
100 - debugInfo: new WeakRef((resource: Promise<any>)),
101 - stack: parseStackTrace(new Error(), 1),
127 + stack: parseStackTrace(new Error(), 5),
128 start: performance.now(),
129 end: -1.1, // Set when we resolve.
130 + promise: new WeakRef((resource: Promise<any>)),
131 awaited:
132 trigger === undefined
133 ? null // It might get overridden when we resolve.
@@ -118,10 +145,10 @@ export function initAsyncDebugInfo(): void {
145 node = ({
146 tag: IO_NODE,
147 owner: resolveOwner(),
121 - debugInfo: null,
122 - stack: parseStackTrace(new Error(), 1), // This is only used if no native promises are used.
148 + stack: parseStackTrace(new Error(), 3), // This is only used if no native promises are used.
149 start: performance.now(),
150 end: -1.1, // Only set when pinged.
151 + promise: null,
152 awaited: null,
153 previous: null,
154 }: IONode);
@@ -133,10 +160,10 @@ export function initAsyncDebugInfo(): void {
160 node = ({
161 tag: IO_NODE,
162 owner: resolveOwner(),
136 - debugInfo: null,
137 - stack: parseStackTrace(new Error(), 1),
163 + stack: parseStackTrace(new Error(), 3),
164 start: performance.now(),
165 end: -1.1, // Only set when pinged.
166 + promise: null,
167 awaited: null,
168 previous: trigger,
169 }: IONode);
packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js
+313 -224
@@ -50,6 +50,23 @@ function normalizeIOInfo(ioInfo) {
50 if (typeof ioInfo.end === 'number') {
51 copy.end = 0;
52 }
53 + const promise = ioInfo.value;
54 + if (promise) {
55 + promise.then(); // init
56 + if (promise.status === 'fulfilled') {
57 + copy.value = {
58 + value: promise.value,
59 + };
60 + } else if (promise.status === 'rejected') {
61 + copy.value = {
62 + reason: promise.reason,
63 + };
64 + } else {
65 + copy.value = {
66 + status: promise.status,
67 + };
68 + }
69 + }
70 return copy;
71 }
72
@@ -129,6 +146,16 @@ describe('ReactFlightAsyncDebugInfo', () => {
146 Stream = require('stream');
147 });
148
149 + function finishLoadingStream(readable) {
150 + return new Promise(resolve => {
151 + if (readable.readableEnded) {
152 + resolve();
153 + } else {
154 + readable.on('end', () => resolve());
155 + }
156 + });
157 + }
158 +
159 function delay(timeout) {
160 return new Promise(resolve => {
161 setTimeout(resolve, timeout);
@@ -183,6 +210,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
210 stream.pipe(readable);
211
212 expect(await result).toBe('HI, SEB');
213 +
214 + await finishLoadingStream(readable);
215 if (
216 __DEV__ &&
217 gate(
@@ -204,9 +233,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
233 [
234 "Object.<anonymous>",
235 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
207 - 175,
236 + 202,
237 109,
209 - 155,
238 + 182,
239 50,
240 ],
241 ],
@@ -228,9 +257,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
257 [
258 "Object.<anonymous>",
259 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
231 - 175,
260 + 202,
261 109,
233 - 155,
262 + 182,
263 50,
264 ],
265 ],
@@ -239,29 +268,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
268 [
269 "delay",
270 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
242 - 133,
271 + 160,
272 12,
244 - 132,
273 + 159,
274 3,
275 ],
276 [
277 "getData",
278 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
250 - 157,
279 + 184,
280 13,
252 - 156,
281 + 183,
282 5,
283 ],
284 [
285 "Component",
286 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
258 - 164,
287 + 191,
288 26,
260 - 163,
289 + 190,
290 5,
291 ],
292 ],
293 "start": 0,
294 + "value": {
295 + "value": undefined,
296 + },
297 },
298 "env": "Server",
299 "owner": {
@@ -273,9 +305,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
305 [
306 "Object.<anonymous>",
307 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
276 - 175,
308 + 202,
309 109,
278 - 155,
310 + 182,
311 50,
312 ],
313 ],
@@ -284,17 +316,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
316 [
317 "getData",
318 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
287 - 157,
319 + 184,
320 13,
289 - 156,
321 + 183,
322 5,
323 ],
324 [
325 "Component",
326 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
295 - 164,
327 + 191,
328 26,
297 - 163,
329 + 190,
330 5,
331 ],
332 ],
@@ -319,9 +351,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
351 [
352 "Object.<anonymous>",
353 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
322 - 175,
354 + 202,
355 109,
324 - 155,
356 + 182,
357 50,
358 ],
359 ],
@@ -330,29 +362,34 @@ describe('ReactFlightAsyncDebugInfo', () => {
362 [
363 "delay",
364 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
333 - 133,
365 + 160,
366 12,
335 - 132,
367 + 159,
368 3,
369 ],
370 [
371 "getData",
372 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
341 - 158,
373 + 185,
374 21,
343 - 156,
375 + 183,
376 5,
377 ],
378 [
379 "Component",
380 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
349 - 164,
381 + 191,
382 20,
351 - 163,
383 + 190,
384 5,
385 ],
386 ],
387 "start": 0,
388 + "value": {
389 + "value": [
390 + ,
391 + ],
392 + },
393 },
394 "env": "Server",
395 "owner": {
@@ -364,9 +401,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
401 [
402 "Object.<anonymous>",
403 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
367 - 175,
404 + 202,
405 109,
369 - 155,
406 + 182,
407 50,
408 ],
409 ],
@@ -375,17 +412,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
412 [
413 "getData",
414 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
378 - 159,
415 + 186,
416 21,
380 - 156,
417 + 183,
418 5,
419 ],
420 [
421 "Component",
422 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
386 - 164,
423 + 191,
424 20,
388 - 163,
425 + 190,
426 5,
427 ],
428 ],
@@ -405,9 +442,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
442 [
443 "Component",
444 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
408 - 166,
445 + 193,
446 60,
410 - 163,
447 + 190,
448 5,
449 ],
450 ],
@@ -429,9 +466,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
466 [
467 "Object.<anonymous>",
468 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
432 - 175,
469 + 202,
470 109,
434 - 155,
471 + 182,
472 50,
473 ],
474 ],
@@ -440,21 +477,24 @@ describe('ReactFlightAsyncDebugInfo', () => {
477 [
478 "delay",
479 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
443 - 133,
480 + 160,
481 12,
445 - 132,
482 + 159,
483 3,
484 ],
485 [
486 "getData",
487 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
451 - 158,
488 + 185,
489 21,
453 - 156,
490 + 183,
491 5,
492 ],
493 ],
494 "start": 0,
495 + "value": {
496 + "status": "halted",
497 + },
498 },
499 "env": "Server",
500 "owner": {
@@ -466,9 +506,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
506 [
507 "Component",
508 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
469 - 166,
509 + 193,
510 60,
471 - 163,
511 + 190,
512 5,
513 ],
514 ],
@@ -477,9 +517,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
517 [
518 "InnerComponent",
519 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
480 - 172,
520 + 199,
521 35,
482 - 169,
522 + 196,
523 5,
524 ],
525 ],
@@ -530,6 +570,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
570 stream.pipe(readable);
571
572 expect(await result).toBe('HI, SEB');
573 +
574 + await finishLoadingStream(readable);
575 if (
576 __DEV__ &&
577 gate(
@@ -551,9 +593,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
593 [
594 "Object.<anonymous>",
595 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
554 - 517,
596 + 557,
597 40,
556 - 498,
598 + 538,
599 49,
600 ],
601 ],
@@ -575,9 +617,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
617 [
618 "Object.<anonymous>",
619 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
578 - 517,
620 + 557,
621 40,
580 - 498,
622 + 538,
623 49,
624 ],
625 ],
@@ -586,29 +628,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
628 [
629 "delay",
630 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
589 - 133,
631 + 160,
632 12,
591 - 132,
633 + 159,
634 3,
635 ],
636 [
637 "getData",
638 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
597 - 500,
639 + 540,
640 13,
599 - 499,
641 + 539,
642 5,
643 ],
644 [
645 "Component",
646 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
605 - 505,
647 + 545,
648 36,
607 - 504,
649 + 544,
650 5,
651 ],
652 ],
653 "start": 0,
654 + "value": {
655 + "value": undefined,
656 + },
657 },
658 "env": "Server",
659 "owner": {
@@ -620,9 +665,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
665 [
666 "Object.<anonymous>",
667 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
623 - 517,
668 + 557,
669 40,
625 - 498,
670 + 538,
671 49,
672 ],
673 ],
@@ -631,17 +676,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
676 [
677 "getData",
678 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
634 - 500,
679 + 540,
680 13,
636 - 499,
681 + 539,
682 5,
683 ],
684 [
685 "Component",
686 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
642 - 505,
687 + 545,
688 36,
644 - 504,
689 + 544,
690 5,
691 ],
692 ],
@@ -661,9 +706,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
706 [
707 "Component",
708 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
664 - 507,
709 + 547,
710 60,
666 - 504,
711 + 544,
712 5,
713 ],
714 ],
@@ -682,9 +727,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
727 [
728 "Object.<anonymous>",
729 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
685 - 517,
730 + 557,
731 40,
687 - 498,
732 + 538,
733 49,
734 ],
735 ],
@@ -693,29 +738,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
738 [
739 "delay",
740 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
696 - 133,
741 + 160,
742 12,
698 - 132,
743 + 159,
744 3,
745 ],
746 [
747 "getData",
748 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
704 - 500,
749 + 540,
750 13,
706 - 499,
751 + 539,
752 5,
753 ],
754 [
755 "Component",
756 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
712 - 506,
757 + 546,
758 22,
714 - 504,
759 + 544,
760 5,
761 ],
762 ],
763 "start": 0,
764 + "value": {
765 + "value": undefined,
766 + },
767 },
768 "env": "Server",
769 "owner": {
@@ -727,9 +775,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
775 [
776 "Component",
777 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
730 - 507,
778 + 547,
779 60,
732 - 504,
780 + 544,
781 5,
782 ],
783 ],
@@ -738,9 +786,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
786 [
787 "InnerComponent",
788 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
741 - 513,
789 + 553,
790 40,
743 - 510,
791 + 550,
792 5,
793 ],
794 ],
@@ -780,6 +828,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
828 stream.pipe(readable);
829
830 expect(await result).toBe('hi');
831 +
832 + await finishLoadingStream(readable);
833 if (
834 __DEV__ &&
835 gate(
@@ -801,9 +851,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
851 [
852 "Object.<anonymous>",
853 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
804 - 772,
854 + 820,
855 109,
806 - 759,
856 + 807,
857 67,
858 ],
859 ],
@@ -822,9 +872,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
872 [
873 "Object.<anonymous>",
874 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
825 - 772,
875 + 820,
876 109,
827 - 759,
877 + 807,
878 67,
879 ],
880 ],
@@ -833,9 +883,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
883 [
884 "Component",
885 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
836 - 762,
886 + 810,
887 7,
838 - 760,
888 + 808,
889 5,
890 ],
891 ],
@@ -874,6 +924,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
924 stream.pipe(readable);
925
926 expect(await result).toBe('hi');
927 +
928 + await finishLoadingStream(readable);
929 if (
930 __DEV__ &&
931 gate(
@@ -895,9 +947,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
947 [
948 "Object.<anonymous>",
949 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
898 - 866,
950 + 916,
951 109,
900 - 857,
952 + 907,
953 94,
954 ],
955 ],
@@ -945,6 +997,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
997 stream.pipe(readable);
998
999 expect(await result).toBe('HI');
1000 +
1001 + await finishLoadingStream(readable);
1002 if (
1003 __DEV__ &&
1004 gate(
@@ -966,9 +1020,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1020 [
1021 "Object.<anonymous>",
1022 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
969 - 937,
1023 + 989,
1024 109,
971 - 913,
1025 + 965,
1026 50,
1027 ],
1028 ],
@@ -1027,6 +1081,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
1081 stream.pipe(readable);
1082
1083 expect(await result).toBe('HI');
1084 +
1085 + await finishLoadingStream(readable);
1086 if (
1087 __DEV__ &&
1088 gate(
@@ -1048,9 +1104,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1104 [
1105 "Object.<anonymous>",
1106 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1051 - 1019,
1107 + 1073,
1108 109,
1053 - 1002,
1109 + 1056,
1110 63,
1111 ],
1112 ],
@@ -1067,17 +1123,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1123 [
1124 "fetchThirdParty",
1125 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1070 - 140,
1126 + 167,
1127 40,
1072 - 138,
1128 + 165,
1129 3,
1130 ],
1131 [
1132 "Component",
1133 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1078 - 1015,
1134 + 1069,
1135 24,
1080 - 1014,
1136 + 1068,
1137 5,
1138 ],
1139 ],
@@ -1099,17 +1155,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1155 [
1156 "fetchThirdParty",
1157 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1102 - 140,
1158 + 167,
1159 40,
1104 - 138,
1160 + 165,
1161 3,
1162 ],
1163 [
1164 "Component",
1165 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1110 - 1015,
1166 + 1069,
1167 24,
1112 - 1014,
1168 + 1068,
1169 5,
1170 ],
1171 ],
@@ -1118,29 +1174,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
1174 [
1175 "delay",
1176 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1121 - 133,
1177 + 160,
1178 12,
1123 - 132,
1179 + 159,
1180 3,
1181 ],
1182 [
1183 "getData",
1184 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1129 - 1004,
1185 + 1058,
1186 13,
1131 - 1003,
1187 + 1057,
1188 5,
1189 ],
1190 [
1191 "ThirdPartyComponent",
1192 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1137 - 1010,
1193 + 1064,
1194 24,
1139 - 1009,
1195 + 1063,
1196 5,
1197 ],
1198 ],
1199 "start": 0,
1200 + "value": {
1201 + "value": undefined,
1202 + },
1203 },
1204 "env": "third-party",
1205 "owner": {
@@ -1152,17 +1211,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1211 [
1212 "fetchThirdParty",
1213 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1155 - 140,
1214 + 167,
1215 40,
1157 - 138,
1216 + 165,
1217 3,
1218 ],
1219 [
1220 "Component",
1221 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1163 - 1015,
1222 + 1069,
1223 24,
1165 - 1014,
1224 + 1068,
1225 5,
1226 ],
1227 ],
@@ -1171,17 +1230,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1230 [
1231 "getData",
1232 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1174 - 1004,
1233 + 1058,
1234 13,
1176 - 1003,
1235 + 1057,
1236 5,
1237 ],
1238 [
1239 "ThirdPartyComponent",
1240 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1182 - 1010,
1241 + 1064,
1242 24,
1184 - 1009,
1243 + 1063,
1244 5,
1245 ],
1246 ],
@@ -1206,17 +1265,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1265 [
1266 "fetchThirdParty",
1267 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1209 - 140,
1268 + 167,
1269 40,
1211 - 138,
1270 + 165,
1271 3,
1272 ],
1273 [
1274 "Component",
1275 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1217 - 1015,
1276 + 1069,
1277 24,
1219 - 1014,
1278 + 1068,
1279 5,
1280 ],
1281 ],
@@ -1225,29 +1284,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
1284 [
1285 "delay",
1286 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1228 - 133,
1287 + 160,
1288 12,
1230 - 132,
1289 + 159,
1290 3,
1291 ],
1292 [
1293 "getData",
1294 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1236 - 1005,
1295 + 1059,
1296 13,
1238 - 1003,
1297 + 1057,
1298 5,
1299 ],
1300 [
1301 "ThirdPartyComponent",
1302 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1244 - 1010,
1303 + 1064,
1304 18,
1246 - 1009,
1305 + 1063,
1306 5,
1307 ],
1308 ],
1309 "start": 0,
1310 + "value": {
1311 + "value": undefined,
1312 + },
1313 },
1314 "env": "third-party",
1315 "owner": {
@@ -1259,17 +1321,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1321 [
1322 "fetchThirdParty",
1323 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1262 - 140,
1324 + 167,
1325 40,
1264 - 138,
1326 + 165,
1327 3,
1328 ],
1329 [
1330 "Component",
1331 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1270 - 1015,
1332 + 1069,
1333 24,
1272 - 1014,
1334 + 1068,
1335 5,
1336 ],
1337 ],
@@ -1278,17 +1340,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1340 [
1341 "getData",
1342 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1281 - 1005,
1343 + 1059,
1344 13,
1283 - 1003,
1345 + 1057,
1346 5,
1347 ],
1348 [
1349 "ThirdPartyComponent",
1350 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1289 - 1010,
1351 + 1064,
1352 18,
1291 - 1009,
1353 + 1063,
1354 5,
1355 ],
1356 ],
@@ -1340,6 +1402,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
1402 stream.pipe(readable);
1403
1404 expect(await result).toBe('HI, Seb');
1405 +
1406 + await finishLoadingStream(readable);
1407 if (
1408 __DEV__ &&
1409 gate(
@@ -1361,9 +1425,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1425 [
1426 "Object.<anonymous>",
1427 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1364 - 1327,
1428 + 1389,
1429 40,
1366 - 1310,
1430 + 1372,
1431 62,
1432 ],
1433 ],
@@ -1385,9 +1449,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1449 [
1450 "Object.<anonymous>",
1451 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1388 - 1327,
1452 + 1389,
1453 40,
1390 - 1310,
1454 + 1372,
1455 62,
1456 ],
1457 ],
@@ -1396,29 +1460,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
1460 [
1461 "delay",
1462 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1399 - 133,
1463 + 160,
1464 12,
1401 - 132,
1465 + 159,
1466 3,
1467 ],
1468 [
1469 "getData",
1470 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1407 - 1312,
1471 + 1374,
1472 13,
1409 - 1311,
1473 + 1373,
1474 25,
1475 ],
1476 [
1477 "Component",
1478 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1415 - 1322,
1479 + 1384,
1480 13,
1417 - 1321,
1481 + 1383,
1482 5,
1483 ],
1484 ],
1485 "start": 0,
1486 + "value": {
1487 + "value": undefined,
1488 + },
1489 },
1490 "env": "Server",
1491 "owner": {
@@ -1430,9 +1497,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1497 [
1498 "Object.<anonymous>",
1499 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1433 - 1327,
1500 + 1389,
1501 40,
1435 - 1310,
1502 + 1372,
1503 62,
1504 ],
1505 ],
@@ -1441,17 +1508,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1508 [
1509 "getData",
1510 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1444 - 1312,
1511 + 1374,
1512 13,
1446 - 1311,
1513 + 1373,
1514 25,
1515 ],
1516 [
1517 "Component",
1518 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1452 - 1322,
1519 + 1384,
1520 13,
1454 - 1321,
1521 + 1383,
1522 5,
1523 ],
1524 ],
@@ -1471,9 +1538,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1538 [
1539 "Component",
1540 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1474 - 1323,
1541 + 1385,
1542 60,
1476 - 1321,
1543 + 1383,
1544 5,
1545 ],
1546 ],
@@ -1495,9 +1562,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1562 [
1563 "Object.<anonymous>",
1564 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1498 - 1327,
1565 + 1389,
1566 40,
1500 - 1310,
1567 + 1372,
1568 62,
1569 ],
1570 ],
@@ -1506,29 +1573,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
1573 [
1574 "delay",
1575 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1509 - 133,
1576 + 160,
1577 12,
1511 - 132,
1578 + 159,
1579 3,
1580 ],
1581 [
1582 "getData",
1583 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1517 - 1312,
1584 + 1374,
1585 13,
1519 - 1311,
1586 + 1373,
1587 25,
1588 ],
1589 [
1590 "Component",
1591 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1525 - 1322,
1592 + 1384,
1593 13,
1527 - 1321,
1594 + 1383,
1595 5,
1596 ],
1597 ],
1598 "start": 0,
1599 + "value": {
1600 + "value": undefined,
1601 + },
1602 },
1603 "env": "Server",
1604 "owner": {
@@ -1540,9 +1610,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1610 [
1611 "Component",
1612 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1543 - 1323,
1613 + 1385,
1614 60,
1545 - 1321,
1615 + 1383,
1616 5,
1617 ],
1618 ],
@@ -1551,9 +1621,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1621 [
1622 "Child",
1623 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1554 - 1317,
1624 + 1379,
1625 28,
1556 - 1316,
1626 + 1378,
1627 5,
1628 ],
1629 ],
@@ -1601,6 +1671,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
1671 stream.pipe(readable);
1672
1673 expect(await result).toBe('HI');
1674 +
1675 + await finishLoadingStream(readable);
1676 if (
1677 __DEV__ &&
1678 gate(
@@ -1622,9 +1694,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1694 [
1695 "Object.<anonymous>",
1696 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1625 - 1588,
1697 + 1658,
1698 40,
1627 - 1572,
1699 + 1642,
1700 57,
1701 ],
1702 ],
@@ -1646,9 +1718,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1718 [
1719 "Object.<anonymous>",
1720 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1649 - 1588,
1721 + 1658,
1722 40,
1651 - 1572,
1723 + 1642,
1724 57,
1725 ],
1726 ],
@@ -1657,29 +1729,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
1729 [
1730 "delay",
1731 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1660 - 133,
1732 + 160,
1733 12,
1662 - 132,
1734 + 159,
1735 3,
1736 ],
1737 [
1738 "getData",
1739 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1668 - 1574,
1740 + 1644,
1741 13,
1670 - 1573,
1742 + 1643,
1743 25,
1744 ],
1745 [
1746 "Component",
1747 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1676 - 1583,
1748 + 1653,
1749 23,
1678 - 1582,
1750 + 1652,
1751 5,
1752 ],
1753 ],
1754 "start": 0,
1755 + "value": {
1756 + "value": undefined,
1757 + },
1758 },
1759 "env": "Server",
1760 "owner": {
@@ -1691,9 +1766,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1766 [
1767 "Object.<anonymous>",
1768 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1694 - 1588,
1769 + 1658,
1770 40,
1696 - 1572,
1771 + 1642,
1772 57,
1773 ],
1774 ],
@@ -1702,17 +1777,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
1777 [
1778 "getData",
1779 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1705 - 1574,
1780 + 1644,
1781 13,
1707 - 1573,
1782 + 1643,
1783 25,
1784 ],
1785 [
1786 "Component",
1787 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1713 - 1583,
1788 + 1653,
1789 23,
1715 - 1582,
1790 + 1652,
1791 5,
1792 ],
1793 ],
@@ -1732,9 +1807,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1807 [
1808 "Component",
1809 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1735 - 1584,
1810 + 1654,
1811 60,
1737 - 1582,
1812 + 1652,
1813 5,
1814 ],
1815 ],
@@ -1753,9 +1828,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1828 [
1829 "Object.<anonymous>",
1830 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1756 - 1588,
1831 + 1658,
1832 40,
1758 - 1572,
1833 + 1642,
1834 57,
1835 ],
1836 ],
@@ -1764,29 +1839,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
1839 [
1840 "delay",
1841 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1767 - 133,
1842 + 160,
1843 12,
1769 - 132,
1844 + 159,
1845 3,
1846 ],
1847 [
1848 "getData",
1849 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1775 - 1574,
1850 + 1644,
1851 13,
1777 - 1573,
1852 + 1643,
1853 25,
1854 ],
1855 [
1856 "Component",
1857 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1783 - 1583,
1858 + 1653,
1859 23,
1785 - 1582,
1860 + 1652,
1861 5,
1862 ],
1863 ],
1864 "start": 0,
1865 + "value": {
1866 + "value": undefined,
1867 + },
1868 },
1869 "env": "Server",
1870 },
@@ -1835,6 +1913,8 @@ describe('ReactFlightAsyncDebugInfo', () => {
1913 stream.pipe(readable);
1914
1915 expect(await result).toBe('hi');
1916 +
1917 + await finishLoadingStream(readable);
1918 if (
1919 __DEV__ &&
1920 gate(
@@ -1856,9 +1936,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1936 [
1937 "Object.<anonymous>",
1938 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1859 - 1822,
1939 + 1900,
1940 40,
1861 - 1804,
1941 + 1882,
1942 80,
1943 ],
1944 ],
@@ -1880,9 +1960,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
1960 [
1961 "Object.<anonymous>",
1962 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1883 - 1822,
1963 + 1900,
1964 40,
1885 - 1804,
1965 + 1882,
1966 80,
1967 ],
1968 ],
@@ -1891,29 +1971,32 @@ describe('ReactFlightAsyncDebugInfo', () => {
1971 [
1972 "delay",
1973 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1894 - 133,
1974 + 160,
1975 12,
1896 - 132,
1976 + 159,
1977 3,
1978 ],
1979 [
1980 "delayTrice",
1981 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1902 - 1812,
1982 + 1890,
1983 13,
1904 - 1810,
1984 + 1888,
1985 5,
1986 ],
1987 [
1988 "Bar",
1989 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1910 - 1817,
1990 + 1895,
1991 13,
1912 - 1816,
1992 + 1894,
1993 5,
1994 ],
1995 ],
1996 "start": 0,
1997 + "value": {
1998 + "value": undefined,
1999 + },
2000 },
2001 "env": "Server",
2002 "owner": {
@@ -1925,9 +2008,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
2008 [
2009 "Object.<anonymous>",
2010 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1928 - 1822,
2011 + 1900,
2012 40,
1930 - 1804,
2013 + 1882,
2014 80,
2015 ],
2016 ],
@@ -1936,17 +2019,17 @@ describe('ReactFlightAsyncDebugInfo', () => {
2019 [
2020 "delayTrice",
2021 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1939 - 1812,
2022 + 1890,
2023 13,
1941 - 1810,
2024 + 1888,
2025 5,
2026 ],
2027 [
2028 "Bar",
2029 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1947 - 1817,
2030 + 1895,
2031 13,
1949 - 1816,
2032 + 1894,
2033 5,
2034 ],
2035 ],
@@ -1968,9 +2051,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
2051 [
2052 "Object.<anonymous>",
2053 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1971 - 1822,
2054 + 1900,
2055 40,
1973 - 1804,
2056 + 1882,
2057 80,
2058 ],
2059 ],
@@ -1979,37 +2062,40 @@ describe('ReactFlightAsyncDebugInfo', () => {
2062 [
2063 "delay",
2064 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1982 - 133,
2065 + 160,
2066 12,
1984 - 132,
2067 + 159,
2068 3,
2069 ],
2070 [
2071 "delayTwice",
2072 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1990 - 1806,
2073 + 1884,
2074 13,
1992 - 1805,
2075 + 1883,
2076 5,
2077 ],
2078 [
2079 "delayTrice",
2080 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
1998 - 1811,
2081 + 1889,
2082 15,
2000 - 1810,
2083 + 1888,
2084 5,
2085 ],
2086 [
2087 "Bar",
2088 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2006 - 1817,
2089 + 1895,
2090 13,
2008 - 1816,
2091 + 1894,
2092 5,
2093 ],
2094 ],
2095 "start": 0,
2096 + "value": {
2097 + "value": undefined,
2098 + },
2099 },
2100 "env": "Server",
2101 "owner": {
@@ -2021,9 +2107,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
2107 [
2108 "Object.<anonymous>",
2109 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2024 - 1822,
2110 + 1900,
2111 40,
2026 - 1804,
2112 + 1882,
2113 80,
2114 ],
2115 ],
@@ -2032,25 +2118,25 @@ describe('ReactFlightAsyncDebugInfo', () => {
2118 [
2119 "delayTwice",
2120 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2035 - 1806,
2121 + 1884,
2122 13,
2037 - 1805,
2123 + 1883,
2124 5,
2125 ],
2126 [
2127 "delayTrice",
2128 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2043 - 1811,
2129 + 1889,
2130 15,
2045 - 1810,
2131 + 1888,
2132 5,
2133 ],
2134 [
2135 "Bar",
2136 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2051 - 1817,
2137 + 1895,
2138 13,
2053 - 1816,
2139 + 1894,
2140 5,
2141 ],
2142 ],
@@ -2072,9 +2158,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
2158 [
2159 "Object.<anonymous>",
2160 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2075 - 1822,
2161 + 1900,
2162 40,
2077 - 1804,
2163 + 1882,
2164 80,
2165 ],
2166 ],
@@ -2083,21 +2169,24 @@ describe('ReactFlightAsyncDebugInfo', () => {
2169 [
2170 "delay",
2171 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2086 - 133,
2172 + 160,
2173 12,
2088 - 132,
2174 + 159,
2175 3,
2176 ],
2177 [
2178 "delayTwice",
2179 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2094 - 1807,
2180 + 1885,
2181 13,
2096 - 1805,
2182 + 1883,
2183 5,
2184 ],
2185 ],
2186 "start": 0,
2187 + "value": {
2188 + "value": undefined,
2189 + },
2190 },
2191 "env": "Server",
2192 "owner": {
@@ -2109,9 +2198,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
2198 [
2199 "Object.<anonymous>",
2200 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2112 - 1822,
2201 + 1900,
2202 40,
2114 - 1804,
2203 + 1882,
2204 80,
2205 ],
2206 ],
@@ -2120,9 +2209,9 @@ describe('ReactFlightAsyncDebugInfo', () => {
2209 [
2210 "delayTwice",
2211 "/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js",
2123 - 1807,
2212 + 1885,
2213 13,
2125 - 1805,
2214 + 1883,
2215 5,
2216 ],
2217 ],
packages/shared/ReactTypes.js
+1
@@ -234,6 +234,7 @@ export type ReactIOInfo = {
234 +name: string, // the name of the async function being called (e.g. "fetch")
235 +start: number, // the start time
236 +end: number, // the end time (this might be different from the time the await was unblocked)
237 + +value?: null | Promise<mixed>, // the Promise that was awaited if any, may be rejected
238 +env?: string, // the environment where this I/O was spawned.
239 +owner?: null | ReactComponentInfo,
240 +stack?: null | ReactStackTrace,