@@ -30,6 +30,24 @@ import {enableAsyncDebugInfo} from 'shared/ReactFeatureFlags';
30
30
const pendingOperations : Map < number , AsyncSequence > =
31
31
__DEV__ && enableAsyncDebugInfo ? new Map ( ) : ( null : any ) ;
32
32
33
+ function resolvePromiseOrAwaitNode (
34
+ unresolvedNode : UnresolvedAwaitNode | UnresolvedPromiseNode ,
35
+ endTime : number ,
36
+ ) : AwaitNode | PromiseNode {
37
+ const resolvedNode : AwaitNode | PromiseNode = ( unresolvedNode : any ) ;
38
+ resolvedNode . tag = ( ( unresolvedNode . tag === UNRESOLVED_PROMISE_NODE
39
+ ? PROMISE_NODE
40
+ : AWAIT_NODE ) : any ) ;
41
+ // The Promise can be garbage collected after this so we should extract debugInfo first.
42
+ const promise = unresolvedNode . debugInfo . deref ( ) ;
43
+ resolvedNode . debugInfo =
44
+ promise === undefined || promise . _debugInfo === undefined
45
+ ? null
46
+ : promise . _debugInfo ;
47
+ resolvedNode . end = endTime ;
48
+ return resolvedNode ;
49
+ }
50
+
33
51
// Initialize the tracing of async operations.
34
52
// We do this globally since the async work can potentially eagerly
35
53
// start before the first request and once requests start they can interleave.
@@ -129,42 +147,50 @@ export function initAsyncDebugInfo(): void {
129
147
}
130
148
pendingOperations . set ( asyncId , node ) ;
131
149
} ,
150
+ before ( asyncId : number ) : void {
151
+ const node = pendingOperations . get ( asyncId ) ;
152
+ if ( node !== undefined ) {
153
+ switch ( node . tag ) {
154
+ case IO_NODE : {
155
+ // Log the end time when we resolved the I/O. This can happen
156
+ // more than once if it's a recurring resource like a connection.
157
+ const ioNode : IONode = ( node : any ) ;
158
+ ioNode . end = performance . now ( ) ;
159
+ break ;
160
+ }
161
+ case UNRESOLVED_AWAIT_NODE :
162
+ case UNRESOLVED_PROMISE_NODE : {
163
+ // If we begin before we resolve, that means that this is actually already resolved but
164
+ // the promiseResolve hook is called at the end of the execution. This means that it was
165
+ // actually already resolved when we started so we just use the start time as the end time.
166
+ resolvePromiseOrAwaitNode ( node , node . start ) ;
167
+ break ;
168
+ }
169
+ }
170
+ }
171
+ } ,
132
172
promiseResolve ( asyncId : number ) : void {
133
173
const node = pendingOperations . get ( asyncId ) ;
134
174
if ( node !== undefined ) {
135
175
let resolvedNode : AwaitNode | PromiseNode ;
136
176
switch ( node . tag ) {
137
- case UNRESOLVED_AWAIT_NODE : {
138
- const awaitNode : AwaitNode = ( node : any ) ;
139
- awaitNode . tag = AWAIT_NODE ;
140
- resolvedNode = awaitNode ;
177
+ case UNRESOLVED_AWAIT_NODE :
178
+ case UNRESOLVED_PROMISE_NODE : {
179
+ resolvedNode = resolvePromiseOrAwaitNode ( node , performance . now ( ) ) ;
141
180
break ;
142
181
}
143
- case UNRESOLVED_PROMISE_NODE : {
144
- const promiseNode : PromiseNode = ( node : any ) ;
145
- promiseNode . tag = PROMISE_NODE ;
146
- resolvedNode = promiseNode ;
182
+ case AWAIT_NODE :
183
+ case PROMISE_NODE : {
184
+ resolvedNode = node ;
185
+ // We already resolved this in the begin phase.
147
186
break ;
148
187
}
149
- case IO_NODE :
150
- // eslint-disable-next-line react-internal/prod-error-codes
151
- throw new Error (
152
- 'A Promise should never be an IO_NODE. This is a bug in React.' ,
153
- ) ;
154
188
default :
155
189
// eslint-disable-next-line react-internal/prod-error-codes
156
190
throw new Error (
157
- 'A Promise should never be resolved twice . This is a bug in React or Node.js .' ,
191
+ 'A Promise should never be an IO_NODE . This is a bug in React.' ,
158
192
) ;
159
193
}
160
- // Log the end time when we resolved the promise.
161
- resolvedNode . end = performance . now ( ) ;
162
- // The Promise can be garbage collected after this so we should extract debugInfo first.
163
- const promise = node . debugInfo . deref ( ) ;
164
- resolvedNode . debugInfo =
165
- promise === undefined || promise . _debugInfo === undefined
166
- ? null
167
- : promise . _debugInfo ;
168
194
const currentAsyncId = executionAsyncId ( ) ;
169
195
if ( asyncId !== currentAsyncId ) {
170
196
// If the promise was not resolved by itself, then that means that
0 commit comments