@@ -30,6 +30,24 @@ import {enableAsyncDebugInfo} from 'shared/ReactFeatureFlags';
3030const  pendingOperations : Map < number ,  AsyncSequence >  = 
3131  __DEV__  &&  enableAsyncDebugInfo  ? new  Map ( )  : ( null : any ) ; 
3232
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+ 
3351// Initialize the tracing of async operations. 
3452// We do this globally since the async work can potentially eagerly 
3553// start before the first request and once requests start they can interleave. 
@@ -129,42 +147,50 @@ export function initAsyncDebugInfo(): void {
129147        } 
130148        pendingOperations . set ( asyncId ,  node ) ; 
131149      } , 
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+       } , 
132172      promiseResolve ( asyncId : number ) : void  { 
133173        const  node  =  pendingOperations . get ( asyncId ) ; 
134174        if  ( node  !==  undefined )  { 
135175          let  resolvedNode : AwaitNode  |  PromiseNode ; 
136176          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 ( ) ) ; 
141180              break ; 
142181            } 
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. 
147186              break ; 
148187            } 
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-               ) ; 
154188            default :
155189              // eslint-disable-next-line react-internal/prod-error-codes 
156190              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.' , 
158192              ) ; 
159193          } 
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 ; 
168194          const  currentAsyncId  =  executionAsyncId ( ) ; 
169195          if  ( asyncId  !==  currentAsyncId )  { 
170196            // If the promise was not resolved by itself, then that means that 
0 commit comments