677
return null;
678
}
679
680
+function serializeDebugThenable(
681
+ request: Request,
682
+ counter: {objectLimit: number},
683
+ thenable: Thenable<any>,
684
+): string {
685
+ // Like serializeThenable but for renderDebugModel
686
+ request.pendingChunks++;
687
+ const id = request.nextChunkId++;
688
+ const ref = serializePromiseID(id);
689
+ request.writtenDebugObjects.set(thenable, ref);
690
+
691
+ switch (thenable.status) {
692
+ case 'fulfilled': {
693
+ emitOutlinedDebugModelChunk(request, id, counter, thenable.value);
694
+ return ref;
695
+ }
696
+ case 'rejected': {
697
+ const x = thenable.reason;
698
+ if (
699
+ enablePostpone &&
700
+ typeof x === 'object' &&
701
+ x !== null &&
702
+ (x: any).$$typeof === REACT_POSTPONE_TYPE
703
+ ) {
704
+ const postponeInstance: Postpone = (x: any);
705
+ // We don't log this postpone.
706
+ emitPostponeChunk(request, id, postponeInstance);
707
+ } else {
708
+ // We don't log these errors since they didn't actually throw into Flight.
709
+ const digest = '';
710
+ emitErrorChunk(request, id, digest, x);
711
+ }
712
+ return ref;
713
+ }
714
+ }
715
+
716
+ let cancelled = false;
717
+
718
+ thenable.then(
719
+ value => {
720
+ if (cancelled) {
721
+ return;
722
+ }
723
+ cancelled = true;
724
+ if (request.status === ABORTING) {
725
+ emitDebugHaltChunk(request, id);
726
+ enqueueFlush(request);
727
+ return;
728
+ }
729
+ emitOutlinedDebugModelChunk(request, id, counter, value);
730
+ enqueueFlush(request);
731
+ },
732
+ reason => {
733
+ if (cancelled) {
734
+ return;
735
+ }
736
+ cancelled = true;
737
+ if (request.status === ABORTING) {
738
+ emitDebugHaltChunk(request, id);
739
+ enqueueFlush(request);
740
+ return;
741
+ }
742
+ if (
743
+ enablePostpone &&
744
+ typeof reason === 'object' &&
745
+ reason !== null &&
746
+ (reason: any).$$typeof === REACT_POSTPONE_TYPE
747
+ ) {
748
+ const postponeInstance: Postpone = (reason: any);
749
+ // We don't log this postpone.
750
+ emitPostponeChunk(request, id, postponeInstance);
751
+ } else {
752
+ // We don't log these errors since they didn't actually throw into Flight.
753
+ const digest = '';
754
+ emitErrorChunk(request, id, digest, reason);
755
+ }
756
+ enqueueFlush(request);
757
+ },
758
+ );
759
+
760
+ // We don't use scheduleMicrotask here because it doesn't actually schedule a microtask
761
+ // in all our configs which is annoying.
762
+ Promise.resolve().then(() => {
763
+ // If we don't resolve the Promise within a microtask. Leave it as hanging since we
764
+ // don't want to block the render forever on a Promise that might never resolve.
765
+ if (cancelled) {
766
+ return;
767
+ }
768
+ cancelled = true;
769
+ emitDebugHaltChunk(request, id);
770
+ enqueueFlush(request);
771
+ // Clean up the request so we don't leak this forever.
772
+ request = (null: any);
773
+ counter = (null: any);
774
+ });
775
+
776
+ return ref;
777
+}
778
+
779
function serializeThenable(
780
request: Request,
781
task: Task,
2293
return '$L' + id.toString(16);
2294
}
2295
2197
-function serializeInfinitePromise(): string {
2198
- return '$@';
2199
-}
2200
-
2296
function serializePromiseID(id: number): string {
2297
return '$@' + id.toString(16);
2298
}
3609
request.completedRegularChunks.push(processedChunk);
3610
}
3611
3612
+function emitDebugHaltChunk(request: Request, id: number): void {
3613
+ if (!__DEV__) {
3614
+ // These errors should never make it into a build so we don't need to encode them in codes.json
3615
+ // eslint-disable-next-line react-internal/prod-error-codes
3616
+ throw new Error(
3617
+ 'emitDebugHaltChunk should never be called in production mode. This is a bug in React.',
3618
+ );
3619
+ }
3620
+ // This emits a marker that this row will never complete and should intentionally never resolve
3621
+ // even when the client stream is closed. We use just the lack of data to indicate this.
3622
+ const row = id.toString(16) + ':\n';
3623
+ const processedChunk = stringToChunk(row);
3624
+ request.completedRegularChunks.push(processedChunk);
3625
+}
3626
+
3627
function emitDebugChunk(
3628
request: Request,
3629
id: number,
4060
// $FlowFixMe[method-unbinding]
4061
if (typeof value.then === 'function') {
4062
const thenable: Thenable<any> = (value: any);
3953
- switch (thenable.status) {
3954
- case 'fulfilled': {
3955
- return serializePromiseID(
3956
- outlineDebugModel(request, counter, thenable.value),
3957
- );
3958
- }
3959
- case 'rejected': {
3960
- const x = thenable.reason;
3961
- request.pendingChunks++;
3962
- const errorId = request.nextChunkId++;
3963
- if (
3964
- enablePostpone &&
3965
- typeof x === 'object' &&
3966
- x !== null &&
3967
- (x: any).$$typeof === REACT_POSTPONE_TYPE
3968
- ) {
3969
- const postponeInstance: Postpone = (x: any);
3970
- // We don't log this postpone.
3971
- emitPostponeChunk(request, errorId, postponeInstance);
3972
- } else {
3973
- // We don't log these errors since they didn't actually throw into Flight.
3974
- const digest = '';
3975
- emitErrorChunk(request, errorId, digest, x);
3976
- }
3977
- return serializePromiseID(errorId);
3978
- }
3979
- }
3980
- // If it hasn't already resolved (and been instrumented) we just encode an infinite
3981
- // promise that will never resolve.
3982
- return serializeInfinitePromise();
4063
+ return serializeDebugThenable(request, counter, thenable);
4064
}
4065
4066
if (isArray(value)) {
4287
}
4288
}
4289
4209
-function outlineDebugModel(
4290
+function emitOutlinedDebugModelChunk(
4291
request: Request,
4292
+ id: number,
4293
counter: {objectLimit: number},
4294
model: ReactClientValue,
4213
-): number {
4295
+): void {
4296
if (!__DEV__) {
4297
// These errors should never make it into a build so we don't need to encode them in codes.json
4298
// eslint-disable-next-line react-internal/prod-error-codes
4299
throw new Error(
4218
- 'outlineDebugModel should never be called in production mode. This is a bug in React.',
4300
+ 'emitOutlinedDebugModel should never be called in production mode. This is a bug in React.',
4301
);
4302
}
4303
4328
}
4329
}
4330
4249
- const id = request.nextChunkId++;
4331
const prevModelRoot = debugModelRoot;
4332
debugModelRoot = model;
4333
if (typeof model === 'object' && model !== null) {
4347
debugModelRoot = prevModelRoot;
4348
}
4349
4269
- request.pendingChunks++;
4350
const row = id.toString(16) + ':' + json + '\n';
4351
const processedChunk = stringToChunk(row);
4352
request.completedRegularChunks.push(processedChunk);
4353
+}
4354
+
4355
+function outlineDebugModel(
4356
+ request: Request,
4357
+ counter: {objectLimit: number},
4358
+ model: ReactClientValue,
4359
+): number {
4360
+ if (!__DEV__) {
4361
+ // These errors should never make it into a build so we don't need to encode them in codes.json
4362
+ // eslint-disable-next-line react-internal/prod-error-codes
4363
+ throw new Error(
4364
+ 'outlineDebugModel should never be called in production mode. This is a bug in React.',
4365
+ );
4366
+ }
4367
+
4368
+ const id = request.nextChunkId++;
4369
+ request.pendingChunks++;
4370
+ emitOutlinedDebugModelChunk(request, id, counter, model);
4371
return id;
4372
}
4373