@@ -75,6 +75,7 @@ import type {
75
75
AsyncSequence ,
76
76
IONode ,
77
77
PromiseNode ,
78
+ UnresolvedPromiseNode ,
78
79
} from './ReactFlightAsyncSequence' ;
79
80
80
81
import {
@@ -734,6 +735,12 @@ function serializeDebugThenable(
734
735
}
735
736
}
736
737
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
+
737
744
let cancelled = false ;
738
745
739
746
thenable . then (
@@ -804,7 +811,7 @@ function serializeThenable(
804
811
) : number {
805
812
const newTask = createTask (
806
813
request ,
807
- null ,
814
+ ( thenable : any ) , // will be replaced by the value before we retry. used for debug info.
808
815
task . keyPath , // the server component sequence continues through Promise-as-a-child.
809
816
task . implicitSlot ,
810
817
request . abortableTasks ,
@@ -3869,7 +3876,7 @@ function outlineIOInfo(request: Request, ioInfo: ReactIOInfo): void {
3869
3876
3870
3877
function serializeIONode (
3871
3878
request : Request ,
3872
- ioNode : IONode | PromiseNode ,
3879
+ ioNode : IONode | PromiseNode | UnresolvedPromiseNode ,
3873
3880
promiseRef : null | WeakRef < Promise < mixed >> ,
3874
3881
) : string {
3875
3882
const existingRef = request . writtenDebugObjects . get ( ioNode ) ;
@@ -4679,6 +4686,74 @@ function forwardDebugInfoFromCurrentContext(
4679
4686
}
4680
4687
}
4681
4688
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
+
4682
4757
function emitTimingChunk (
4683
4758
request : Request ,
4684
4759
id : number ,
@@ -5028,6 +5103,7 @@ function abortTask(task: Task, request: Request, errorId: number): void {
5028
5103
return ;
5029
5104
}
5030
5105
task . status = ABORTED ;
5106
+ forwardDebugInfoFromAbortedTask ( request , task ) ;
5031
5107
// Track when we aborted this task as its end time.
5032
5108
if ( enableProfilerTimer && enableComponentPerformanceTrack ) {
5033
5109
if ( task . timed ) {
@@ -5047,6 +5123,7 @@ function haltTask(task: Task, request: Request): void {
5047
5123
return ;
5048
5124
}
5049
5125
task . status = ABORTED ;
5126
+ forwardDebugInfoFromAbortedTask ( request , task ) ;
5050
5127
// We don't actually emit anything for this task id because we are intentionally
5051
5128
// leaving the reference unfulfilled.
5052
5129
request . pendingChunks -- ;
0 commit comments