301
rects: null | Array<Rect>, // The bounding rects of content children.
302
suspendedBy: Map<ReactIOInfo, Set<DevToolsInstance>>, // Tracks which data we're suspended by and the children that suspend it.
303
environments: Map<string, number>, // Tracks the Flight environment names that suspended this. I.e. if the server blocked this.
304
+ endTime: number, // Track a short cut to the maximum end time value within the suspendedBy set.
305
// Track whether any of the items in suspendedBy are unique this this Suspense boundaries or if they're all
306
// also in the parent sets. This determine whether this could contribute in the loading sequence.
307
hasUniqueSuspenders: boolean,
331
rects: null,
332
suspendedBy: new Map(),
333
environments: new Map(),
334
+ endTime: 0,
335
hasUniqueSuspenders: false,
336
hasUnknownSuspenders: false,
337
});
2158
// Regular operations
2159
pendingOperations.length +
2160
// All suspender changes are batched in a single message.
2159
- // [SUSPENSE_TREE_OPERATION_SUSPENDERS, suspenderChangesLength, ...[id, hasUniqueSuspenders, isSuspended]]
2160
- (numSuspenderChanges > 0 ? 2 + numSuspenderChanges * 3 : 0),
2161
+ // [SUSPENSE_TREE_OPERATION_SUSPENDERS, suspenderChangesLength, ...[id, hasUniqueSuspenders, endTime, isSuspended]]
2162
+ (numSuspenderChanges > 0 ? 2 + numSuspenderChanges * 4 : 0),
2163
);
2164
2165
// Identify which renderer this update is coming from.
2244
}
2245
operations[i++] = fiberIdWithChanges;
2246
operations[i++] = suspense.hasUniqueSuspenders ? 1 : 0;
2247
+ operations[i++] = Math.round(suspense.endTime * 1000);
2248
const instance = suspense.instance;
2249
const isSuspended =
2250
// TODO: Track if other SuspenseNode like SuspenseList rows are suspended.
2915
// like owner instances to link down into the tree.
2916
if (!suspendedBySet.has(parentInstance)) {
2917
suspendedBySet.add(parentInstance);
2918
+ const virtualEndTime = getVirtualEndTime(ioInfo);
2919
if (
2920
!parentSuspenseNode.hasUniqueSuspenders &&
2921
!ioExistsInSuspenseAncestor(parentSuspenseNode, ioInfo)
2922
) {
2923
// This didn't exist in the parent before, so let's mark this boundary as having a unique suspender.
2924
parentSuspenseNode.hasUniqueSuspenders = true;
2925
+ if (parentSuspenseNode.endTime < virtualEndTime) {
2926
+ parentSuspenseNode.endTime = virtualEndTime;
2927
+ }
2928
+ recordSuspenseSuspenders(parentSuspenseNode);
2929
+ } else if (parentSuspenseNode.endTime < virtualEndTime) {
2930
+ parentSuspenseNode.endTime = virtualEndTime;
2931
recordSuspenseSuspenders(parentSuspenseNode);
2932
}
2933
}
2989
}
2990
}
2991
2992
+ function getVirtualEndTime(ioInfo: ReactIOInfo): number {
2993
+ if (ioInfo.env != null) {
2994
+ // Sort client side content first so that scripts and streams don't
2995
+ // cover up the effect of server time.
2996
+ return ioInfo.end + 1000000;
2997
+ }
2998
+ return ioInfo.end;
2999
+ }
3000
+
3001
+ function computeEndTime(suspenseNode: SuspenseNode) {
3002
+ let maxEndTime = 0;
3003
+ suspenseNode.suspendedBy.forEach((set, ioInfo) => {
3004
+ const virtualEndTime = getVirtualEndTime(ioInfo);
3005
+ if (virtualEndTime > maxEndTime) {
3006
+ maxEndTime = virtualEndTime;
3007
+ }
3008
+ });
3009
+ return maxEndTime;
3010
+ }
3011
+
3012
function removePreviousSuspendedBy(
3013
instance: DevToolsInstance,
3014
previousSuspendedBy: null | Array<ReactAsyncInfo>,
3026
if (previousSuspendedBy !== null && suspenseNode !== null) {
3027
const nextSuspendedBy = instance.suspendedBy;
3028
let changedEnvironment = false;
3029
+ let mayHaveChangedEndTime = false;
3030
for (let i = 0; i < previousSuspendedBy.length; i++) {
3031
const asyncInfo = previousSuspendedBy[i];
3032
if (
3040
const ioInfo = asyncInfo.awaited;
3041
const suspendedBySet = suspenseNode.suspendedBy.get(ioInfo);
3042
3043
+ if (suspenseNode.endTime === getVirtualEndTime(ioInfo)) {
3044
+ // This may be the only remaining entry at this end time. Recompute the end time.
3045
+ mayHaveChangedEndTime = true;
3046
+ }
3047
+
3048
if (
3049
suspendedBySet === undefined ||
3050
!suspendedBySet.delete(instance)
3102
}
3103
}
3104
}
3069
- if (changedEnvironment) {
3105
+ const newEndTime = mayHaveChangedEndTime
3106
+ ? computeEndTime(suspenseNode)
3107
+ : suspenseNode.endTime;
3108
+ if (changedEnvironment || newEndTime !== suspenseNode.endTime) {
3109
+ suspenseNode.endTime = newEndTime;
3110
recordSuspenseSuspenders(suspenseNode);
3111
}
3112
}