359
360
const OPENING = 10;
361
const OPEN = 11;
362
-const ABORTING = 12;
363
-const CLOSING = 13;
364
-const CLOSED = 14;
365
-const STALLED_DEV = 15;
362
+const CLOSING = 12;
363
+const CLOSED = 13;
364
+const STALLED_DEV = 14;
365
366
export opaque type Request = {
367
destination: null | Destination,
370
+renderState: RenderState,
371
+rootFormatContext: FormatContext,
372
+progressiveChunkSize: number,
374
- status: 10 | 11 | 12 | 13 | 14 | 15,
373
+ status: 10 | 11 | 12 | 13 | 14,
374
fatalError: mixed,
375
+ aborted: boolean,
376
nextSegmentId: number,
377
allPendingTasks: number, // when it reaches zero, we can close the connection.
378
pendingRootTasks: number, // when this reaches zero, we've finished at least the root boundary.
530
: progressiveChunkSize;
531
this.status = isWorkLoopExternallyDriven ? OPEN : OPENING;
532
this.fatalError = null;
533
+ this.aborted = false;
534
this.nextSegmentId = 0;
535
this.allPendingTasks = 0;
536
this.pendingRootTasks = 0;
1039
// performWork + retryTask without mutation
1040
function rerenderStalledTask(request: Request, task: Task): void {
1041
const prevStatus = request.status;
1042
+ const prevAborted = request.aborted;
1043
request.status = STALLED_DEV;
1044
+ // This diagnostic replay must reach the suspended call site instead of
1045
+ // taking the abort path.
1046
+ request.aborted = false;
1047
1048
const prevContext = getActiveContext();
1049
const prevDispatcher = ReactSharedInternals.H;
1087
}
1088
currentRequest = prevRequest;
1089
request.status = prevStatus;
1090
+ request.aborted = prevAborted;
1091
}
1092
}
1093
1485
boundarySegment.status = COMPLETED;
1486
finishedSegment(request, parentBoundary, boundarySegment);
1487
} catch (thrownValue: mixed) {
1482
- if (request.status === ABORTING) {
1488
+ if (request.aborted) {
1489
boundarySegment.status = ABORTED;
1490
} else {
1491
boundarySegment.status = ERRORED;
1595
} catch (thrownValue: mixed) {
1596
newBoundary.status = CLIENT_RENDERED;
1597
let error: mixed;
1592
- if (request.status === ABORTING) {
1598
+ if (request.aborted) {
1599
contentRootSegment.status = ABORTED;
1600
error = request.fatalError;
1601
} else {
2081
finishSuspenseListRow(request, previousSuspenseListRow);
2082
}
2083
} catch (thrownValue: mixed) {
2078
- if (request.status === ABORTING) {
2084
+ if (request.aborted) {
2085
newSegment.status = ABORTED;
2086
} else {
2087
newSegment.status = ERRORED;
2398
} else {
2399
nextChildren = instance.render();
2400
}
2395
- if (request.status === ABORTING) {
2401
+ if (request.aborted) {
2402
// eslint-disable-next-line no-throw-literal
2403
throw null;
2404
}
2547
props,
2548
legacyContext,
2549
);
2544
- if (request.status === ABORTING) {
2550
+ if (request.aborted) {
2551
// eslint-disable-next-line no-throw-literal
2552
throw null;
2553
}
2824
const init = lazyComponent._init;
2825
Component = init(payload);
2826
}
2821
- if (
2822
- request.status === ABORTING &&
2823
- // We're going to discard this render anyway.
2824
- // We just need to reach the point where we suspended in dev.
2825
- (!__DEV__ || request.status !== STALLED_DEV)
2826
- ) {
2827
+ if (request.aborted) {
2828
// eslint-disable-next-line no-throw-literal
2829
throw null;
2830
}
3442
const init = lazyNode._init;
3443
resolvedNode = init(payload);
3444
}
3444
- if (request.status === ABORTING) {
3445
+ if (request.aborted) {
3446
// eslint-disable-next-line no-throw-literal
3447
throw null;
3448
}
4186
getSuspendedThenable()
4187
: thrownValue;
4188
4188
- if (request.status === ABORTING) {
4189
+ if (request.aborted) {
4190
// We are aborting so we can just bubble up to the task by falling through
4191
} else if (typeof x === 'object' && x !== null) {
4192
// $FlowFixMe[method-unbinding]
4287
getSuspendedThenable()
4288
: thrownValue;
4289
4289
- if (request.status === ABORTING) {
4290
+ if (request.aborted) {
4291
// We are aborting so we can just bubble up to the task by falling through
4292
} else if (typeof x === 'object' && x !== null) {
4293
// $FlowFixMe[method-unbinding]
5125
// (unstable) API for suspending. This implementation detail can change
5126
// later, once we deprecate the old API in favor of `use`.
5127
getSuspendedThenable()
5127
- : request.status === ABORTING
5128
+ : request.aborted
5129
? request.fatalError
5130
: thrownValue;
5131
5131
- if (request.status === ABORTING && request.trackedPostpones !== null) {
5132
+ if (request.aborted && request.trackedPostpones !== null) {
5133
// We are aborting a prerender and need to halt this task.
5134
const trackedPostpones = request.trackedPostpones;
5135
const thrownInfo = getThrownInfo(task.componentStack);
5251
erroredReplay(
5252
request,
5253
task.blockedBoundary,
5253
- request.status === ABORTING ? request.fatalError : x,
5254
+ request.aborted ? request.fatalError : x,
5255
errorInfo,
5256
task.replay.nodes,
5257
task.replay.slots,
6156
6157
// This is called to early terminate a request. It puts all pending boundaries in client rendered state.
6158
export function abort(request: Request, reason: mixed): void {
6158
- if (request.status !== OPEN && request.status !== OPENING) {
6159
+ if (
6160
+ request.aborted ||
6161
+ (request.status !== OPEN && request.status !== OPENING)
6162
+ ) {
6163
// Only requests that are not already complete or in the process of aborting
6164
// can be aborted. in practice this makes abort callable at most once per render.
6165
return;
6166
}
6163
- request.status = ABORTING;
6167
+ request.aborted = true;
6168
6169
try {
6170
const abortableTasks = request.abortableTasks;