75
AsyncSequence,
76
IONode,
77
PromiseNode,
78
+ UnresolvedPromiseNode,
79
} from './ReactFlightAsyncSequence';
80
81
import {
735
}
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
+
744
let cancelled = false;
745
746
thenable.then(
811
): number {
812
const newTask = createTask(
813
request,
807
- null,
814
+ (thenable: any), // will be replaced by the value before we retry. used for debug info.
815
task.keyPath, // the server component sequence continues through Promise-as-a-child.
816
task.implicitSlot,
817
request.abortableTasks,
3876
3877
function serializeIONode(
3878
request: Request,
3872
- ioNode: IONode | PromiseNode,
3879
+ ioNode: IONode | PromiseNode | UnresolvedPromiseNode,
3880
promiseRef: null | WeakRef<Promise<mixed>>,
3881
): string {
3882
const existingRef = request.writtenDebugObjects.get(ioNode);
4686
}
4687
}
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
+
4757
function emitTimingChunk(
4758
request: Request,
4759
id: number,
5103
return;
5104
}
5105
task.status = ABORTED;
5106
+ forwardDebugInfoFromAbortedTask(request, task);
5107
// Track when we aborted this task as its end time.
5108
if (enableProfilerTimer && enableComponentPerformanceTrack) {
5109
if (task.timed) {
5123
return;
5124
}
5125
task.status = ABORTED;
5126
+ forwardDebugInfoFromAbortedTask(request, task);
5127
// We don't actually emit anything for this task id because we are intentionally
5128
// leaving the reference unfulfilled.
5129
request.pendingChunks--;