@@ -75,6 +75,7 @@ import type {
7575  AsyncSequence , 
7676  IONode , 
7777  PromiseNode , 
78+   UnresolvedAwaitNode , 
7879  UnresolvedPromiseNode , 
7980}  from  './ReactFlightAsyncSequence' ; 
8081
@@ -95,6 +96,7 @@ import {
9596  markAsyncSequenceRootTask , 
9697  getCurrentAsyncSequence , 
9798  getAsyncSequenceFromPromise , 
99+   getInternalAwaitNode , 
98100  parseStackTrace , 
99101  parseStackTracePrivate , 
100102  supportsComponentStorage , 
@@ -2305,7 +2307,18 @@ function visitAsyncNode(
23052307            // We aborted this render. If this Promise spanned the abort time it was probably the 
23062308            // Promise that was aborted. This won't necessarily have I/O associated with it but 
23072309            // it's a point of interest. 
2308-             match  =  node ; 
2310+             // However, if the Promise and IO node have the same owner, it likely means a sync component 
2311+             // created both the Promise and initiated the I/O. Prefer the IO node for more specific info. 
2312+             if  ( 
2313+               ioNode  !==  null  && 
2314+               ioNode . tag  ===  IO_NODE  && 
2315+               node . owner  !==  null  && 
2316+               ioNode . owner  ===  node . owner 
2317+             )  { 
2318+               match  =  ioNode ; 
2319+             }  else  { 
2320+               match  =  node ; 
2321+             } 
23092322          } 
23102323        }  else  if  ( ioNode  !==  null ) { 
23112324          // This Promise was blocked on I/O. That's a signal that this Promise is interesting to log. 
@@ -4417,7 +4430,7 @@ function outlineIOInfo(request: Request, ioInfo: ReactIOInfo): void {
44174430
44184431function  serializeIONode ( 
44194432  request : Request , 
4420-   ioNode : IONode  |  PromiseNode  |  UnresolvedPromiseNode , 
4433+   ioNode : IONode  |  PromiseNode  |  UnresolvedPromiseNode   |   UnresolvedAwaitNode , 
44214434  promiseRef : null  |  WeakRef < Promise < mixed >> , 
44224435) : string  { 
44234436  const  existingRef  =  request . writtenDebugObjects . get ( ioNode ) ; 
@@ -5383,26 +5396,29 @@ function forwardDebugInfoFromAbortedTask(request: Request, task: Task): void {
53835396          // See if any of the dependencies are resolved yet. 
53845397          node  =  node . awaited ; 
53855398        } 
5399+         // For unresolved Promises, check if we have an internal await node that shows what 
5400+         // the async function is currently blocked on. For resolved Promises, the regular 
5401+         // awaited field already contains the necessary information. 
53865402        if  ( node . tag  ===  UNRESOLVED_PROMISE_NODE )  { 
5387-           // We don't know what Promise will eventually end up resolving this Promise and if it 
5388-           // was I/O at all. However, we assume that it was some kind of I/O since it didn't 
5389-           // complete in time before aborting. 
5390-           // The best we can do is try to emit the stack of where this Promise was created. 
5403+           const  internalAwait  =  getInternalAwaitNode ( node ) ; 
5404+           if  ( internalAwait  !==  null )  { 
5405+             node  =  internalAwait ; 
5406+           } 
5407+         } 
5408+         if  ( node . tag  ===  UNRESOLVED_AWAIT_NODE )  { 
5409+           // We found the await that's blocking. Use its stack to show where the component is stuck. 
53915410          serializeIONode ( request ,  node ,  null ) ; 
53925411          request . pendingChunks ++ ; 
53935412          const  env  =  ( 0 ,  request . environmentName ) ( ) ; 
53945413          const  asyncInfo : ReactAsyncInfo  =  { 
5395-             awaited : ( ( node : any ) : ReactIOInfo ) ,   // This is deduped by this reference. 
5414+             awaited : ( ( node : any ) : ReactIOInfo ) , 
53965415            env : env , 
53975416          } ; 
5398-           // We don't have a start time for this await but in case there was no start time emitted 
5399-           // we need to include something. TODO: We should maybe ideally track the time when we 
5400-           // called .then() but without updating the task.time field since that's used for the cutoff. 
54015417          advanceTaskTime ( request ,  task ,  task . time ) ; 
54025418          emitDebugChunk ( request ,  task . id ,  asyncInfo ) ; 
54035419        }  else  { 
5404-           // We have a resolved Promise. Its debug info can include both awaited data and rejected  
5405-           // promises after the abort. 
5420+           // We have a resolved or unresolved  Promise. Its debug info can include both awaited 
5421+           // data and rejected  promises after the abort. 
54065422          emitAsyncSequence ( request ,  task ,  sequence ,  debugInfo ,  null ,  null ) ; 
54075423        } 
54085424      } 
0 commit comments