@@ -75,6 +75,7 @@ import type {
7575 AsyncSequence ,
7676 IONode ,
7777 PromiseNode ,
78+ UnresolvedPromiseNode ,
7879} from './ReactFlightAsyncSequence' ;
7980
8081import {
@@ -734,6 +735,12 @@ function serializeDebugThenable(
734735 }
735736 }
736737
738+ if ( request . status === ABORTING ) {
739+ // Ensure that we have time to emit the halt chunk if we're sync aborting.
740+ emitDebugHaltChunk ( request , id ) ;
741+ return ref ;
742+ }
743+
737744 let cancelled = false ;
738745
739746 thenable . then (
@@ -804,7 +811,7 @@ function serializeThenable(
804811) : number {
805812 const newTask = createTask (
806813 request ,
807- null ,
814+ ( thenable : any ) , // will be replaced by the value before we retry. used for debug info.
808815 task . keyPath , // the server component sequence continues through Promise-as-a-child.
809816 task . implicitSlot ,
810817 request . abortableTasks ,
@@ -3869,7 +3876,7 @@ function outlineIOInfo(request: Request, ioInfo: ReactIOInfo): void {
38693876
38703877function serializeIONode (
38713878 request : Request ,
3872- ioNode : IONode | PromiseNode ,
3879+ ioNode : IONode | PromiseNode | UnresolvedPromiseNode ,
38733880 promiseRef : null | WeakRef < Promise < mixed >> ,
38743881) : string {
38753882 const existingRef = request . writtenDebugObjects . get ( ioNode ) ;
@@ -4679,6 +4686,74 @@ function forwardDebugInfoFromCurrentContext(
46794686 }
46804687}
46814688
4689+ function forwardDebugInfoFromAbortedTask ( request : Request , task : Task ) : void {
4690+ // If a task is aborted, we can still include as much debug info as we can from the
4691+ // value that we have so far.
4692+ const model : any = task . model ;
4693+ if ( typeof model !== 'object ' || model === null ) {
4694+ return ;
4695+ }
4696+ let debugInfo : ?ReactDebugInfo ;
4697+ if ( __DEV__ ) {
4698+ // If this came from Flight, forward any debug info into this new row.
4699+ debugInfo = model . _debugInfo ;
4700+ if ( debugInfo ) {
4701+ forwardDebugInfo ( request , task , debugInfo ) ;
4702+ }
4703+ }
4704+ if (
4705+ enableProfilerTimer &&
4706+ enableComponentPerformanceTrack &&
4707+ enableAsyncDebugInfo
4708+ ) {
4709+ let thenable : null | Thenable < any > = null ;
4710+ if ( typeof model . then === 'function ') {
4711+ thenable = ( model : any ) ;
4712+ } else if ( model . $$typeof === REACT_LAZY_TYPE ) {
4713+ const payload = model . _payload ;
4714+ const init = model . _init ;
4715+ try {
4716+ init ( payload ) ;
4717+ } catch ( x ) {
4718+ if (
4719+ typeof x === 'object ' &&
4720+ x !== null &&
4721+ typeof x . then === 'function '
4722+ ) {
4723+ thenable = ( x : any ) ;
4724+ }
4725+ }
4726+ }
4727+ if ( thenable !== null ) {
4728+ const sequence = getAsyncSequenceFromPromise ( thenable ) ;
4729+ if ( sequence !== null ) {
4730+ let node = sequence ;
4731+ while ( node . tag === UNRESOLVED_AWAIT_NODE && node . awaited !== null ) {
4732+ // See if any of the dependencies are resolved yet.
4733+ node = node . awaited ;
4734+ }
4735+ if ( node . tag === UNRESOLVED_PROMISE_NODE ) {
4736+ // We don't know what Promise will eventually end up resolving this Promise and if it
4737+ // was I/O at all. However, we assume that it was some kind of I/O since it didn't
4738+ // complete in time before aborting.
4739+ // The best we can do is try to emit the stack of where this Promise was created.
4740+ serializeIONode ( request , node , null ) ;
4741+ request . pendingChunks ++ ;
4742+ const env = ( 0 , request . environmentName ) ( ) ;
4743+ const asyncInfo : ReactAsyncInfo = {
4744+ awaited : ( ( node : any ) : ReactIOInfo ) , // This is deduped by this reference.
4745+ env : env ,
4746+ } ;
4747+ emitDebugChunk ( request , task . id , asyncInfo ) ;
4748+ markOperationEndTime ( request , task , performance . now ( ) ) ;
4749+ } else {
4750+ emitAsyncSequence ( request , task , sequence , debugInfo , null , null ) ;
4751+ }
4752+ }
4753+ }
4754+ }
4755+ }
4756+
46824757function emitTimingChunk (
46834758 request : Request ,
46844759 id : number ,
@@ -5028,6 +5103,7 @@ function abortTask(task: Task, request: Request, errorId: number): void {
50285103 return ;
50295104 }
50305105 task . status = ABORTED ;
5106+ forwardDebugInfoFromAbortedTask ( request , task ) ;
50315107 // Track when we aborted this task as its end time.
50325108 if ( enableProfilerTimer && enableComponentPerformanceTrack ) {
50335109 if ( task . timed ) {
@@ -5047,6 +5123,7 @@ function haltTask(task: Task, request: Request): void {
50475123 return ;
50485124 }
50495125 task . status = ABORTED ;
5126+ forwardDebugInfoFromAbortedTask ( request , task ) ;
50505127 // We don't actually emit anything for this task id because we are intentionally
50515128 // leaving the reference unfulfilled.
50525129 request . pendingChunks -- ;
0 commit comments