Skip to content

Commit 019dd90

Browse files
committed
Eagerly encode the serializable nodes
Since we're now assigning IDs eagerly to postponed boundaries and segments we can encode them into their serialized form eagerly. Instead of doing a second pass at the end.
1 parent e96bb09 commit 019dd90

File tree

1 file changed

+43
-66
lines changed

1 file changed

+43
-66
lines changed

packages/react-server/src/ReactFizzServer.js

Lines changed: 43 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,11 @@ type ResumableNode =
187187
number /* segment id */,
188188
];
189189

190-
type PostponedSegment = {
191-
keyPath: KeyNode,
192-
segment: Segment,
190+
type PostponedHoles = {
191+
workingMap: Map<KeyNode, ResumableParentNode>,
192+
root: Array<ResumableNode>,
193193
};
194194

195-
type PostponedHoles = Map<Root | SuspenseBoundary, Array<PostponedSegment>>;
196-
197195
type LegacyContext = {
198196
[key: string]: any,
199197
};
@@ -1681,6 +1679,10 @@ function trackPostpone(
16811679
task: Task,
16821680
segment: Segment,
16831681
): void {
1682+
segment.status = POSTPONED;
1683+
// We know that this will leave a hole so we might as well assign an ID now.
1684+
segment.id = request.nextSegmentId++;
1685+
16841686
const boundary = task.blockedBoundary;
16851687
if (boundary !== null && boundary.status === PENDING) {
16861688
boundary.status = POSTPONED;
@@ -1690,22 +1692,39 @@ function trackPostpone(
16901692
request.renderState,
16911693
request.resumableState,
16921694
);
1695+
1696+
const boundaryKeyPath = boundary.keyPath;
1697+
if (boundaryKeyPath === null) {
1698+
throw new Error(
1699+
'It should not be possible to postpone at the root. This is a bug in React.',
1700+
);
1701+
}
1702+
const children: Array<ResumableNode> = [];
1703+
const boundaryNode: ResumableParentNode = [
1704+
REPLAY_SUSPENSE_BOUNDARY,
1705+
boundaryKeyPath[1],
1706+
boundaryKeyPath[2],
1707+
children,
1708+
boundary.id,
1709+
];
1710+
trackedPostpones.workingMap.set(boundaryKeyPath, boundaryNode);
1711+
addToResumableParent(boundaryNode, boundaryKeyPath, trackedPostpones);
16931712
}
1694-
let postponedSegments = trackedPostpones.get(task.blockedBoundary);
1695-
if (postponedSegments === undefined) {
1696-
// This is the first time we've postponed this boundary.
1697-
postponedSegments = [];
1698-
trackedPostpones.set(task.blockedBoundary, postponedSegments);
1699-
}
1700-
if (task.keyPath === null) {
1713+
1714+
const keyPath = task.keyPath;
1715+
if (keyPath === null) {
17011716
throw new Error(
17021717
'It should not be possible to postpone at the root. This is a bug in React.',
17031718
);
17041719
}
1705-
postponedSegments.push({
1706-
keyPath: task.keyPath,
1707-
segment,
1708-
});
1720+
1721+
const segmentNode: ResumableNode = [
1722+
RESUME_SEGMENT,
1723+
keyPath[1],
1724+
keyPath[2],
1725+
segment.id,
1726+
];
1727+
addToResumableParent(segmentNode, keyPath, trackedPostpones);
17091728
}
17101729

17111730
function injectPostponedHole(
@@ -1727,9 +1746,6 @@ function injectPostponedHole(
17271746
// Assume we are text embedded at the trailing edge
17281747
true,
17291748
);
1730-
newSegment.status = POSTPONED;
1731-
// We know that this will leave a hole so we might as well assign an ID now.
1732-
segment.id = request.nextSegmentId++;
17331749
segment.children.push(newSegment);
17341750
// Reset lastPushedText for current Segment since the new Segment "consumed" it
17351751
segment.lastPushedText = false;
@@ -2200,9 +2216,6 @@ function retryTask(request: Request, task: Task): void {
22002216
// an error.
22012217
const trackedPostpones = request.trackedPostpones;
22022218
task.abortSet.delete(task);
2203-
segment.status = POSTPONED;
2204-
// We know that this will leave a hole so we might as well assign an ID now.
2205-
segment.id = request.nextSegmentId++;
22062219
const postponeInstance: Postpone = (x: any);
22072220
logPostpone(request, postponeInstance.message);
22082221
trackPostpone(request, trackedPostpones, task, segment);
@@ -2703,7 +2716,7 @@ function flushCompletedQueues(
27032716
if (
27042717
!enablePostpone ||
27052718
request.trackedPostpones === null ||
2706-
request.trackedPostpones.size === 0
2719+
request.trackedPostpones.root.length === 0
27072720
) {
27082721
writePostamble(destination, request.resumableState);
27092722
}
@@ -2737,7 +2750,7 @@ export function startRender(request: Request): void {
27372750

27382751
export function startPrerender(request: Request): void {
27392752
// Start tracking postponed holes during this render.
2740-
request.trackedPostpones = new Map();
2753+
request.trackedPostpones = {workingMap: new Map(), root: []};
27412754
startRender(request);
27422755
}
27432756

@@ -2810,13 +2823,13 @@ export function getResumableState(request: Request): ResumableState {
28102823
function addToResumableParent(
28112824
node: ResumableNode,
28122825
keyPath: KeyNode,
2813-
root: Array<ResumableNode>,
2814-
workingMap: Map<KeyNode, ResumableParentNode>,
2826+
trackedPostpones: PostponedHoles,
28152827
): void {
28162828
const parentKeyPath = keyPath[0];
28172829
if (parentKeyPath === null) {
2818-
root.push(node);
2830+
trackedPostpones.root.push(node);
28192831
} else {
2832+
const workingMap = trackedPostpones.workingMap;
28202833
let parentNode = workingMap.get(parentKeyPath);
28212834
if (parentNode === undefined) {
28222835
parentNode = ([
@@ -2826,7 +2839,7 @@ function addToResumableParent(
28262839
([]: Array<ResumableNode>),
28272840
]: ResumableParentNode);
28282841
workingMap.set(parentKeyPath, parentNode);
2829-
addToResumableParent(parentNode, parentKeyPath, root, workingMap);
2842+
addToResumableParent(parentNode, parentKeyPath, trackedPostpones);
28302843
}
28312844
parentNode[3].push(node);
28322845
}
@@ -2843,50 +2856,14 @@ export type PostponedState = {
28432856
// Returns the state of a postponed request or null if nothing was postponed.
28442857
export function getPostponedState(request: Request): null | PostponedState {
28452858
const trackedPostpones = request.trackedPostpones;
2846-
if (trackedPostpones === null || trackedPostpones.size === 0) {
2859+
if (trackedPostpones === null || trackedPostpones.root.length === 0) {
28472860
return null;
28482861
}
2849-
2850-
// Next we build up a traversal tree of the resumable key paths and their
2851-
// paths through suspense boundaries.
2852-
const workingMap: Map<KeyNode, ResumableParentNode> = new Map();
2853-
const root: Array<ResumableNode> = [];
2854-
2855-
trackedPostpones.forEach(function (
2856-
segments: Array<PostponedSegment>,
2857-
boundary: Root | SuspenseBoundary,
2858-
) {
2859-
if (boundary !== null && boundary.keyPath !== null) {
2860-
const keyPath = boundary.keyPath;
2861-
const children: Array<ResumableNode> = [];
2862-
const boundaryNode: ResumableParentNode = [
2863-
REPLAY_SUSPENSE_BOUNDARY,
2864-
keyPath[1],
2865-
keyPath[2],
2866-
children,
2867-
boundary.id,
2868-
];
2869-
workingMap.set(boundary.keyPath, boundaryNode);
2870-
addToResumableParent(boundaryNode, keyPath, root, workingMap);
2871-
}
2872-
for (let i = 0; i < segments.length; i++) {
2873-
const postponedSegment = segments[i];
2874-
const keyPath = postponedSegment.keyPath;
2875-
const segmentNode: ResumableNode = [
2876-
RESUME_SEGMENT,
2877-
keyPath[1],
2878-
keyPath[2],
2879-
postponedSegment.segment.id,
2880-
];
2881-
addToResumableParent(segmentNode, keyPath, root, workingMap);
2882-
}
2883-
});
2884-
28852862
return {
28862863
nextSegmentId: request.nextSegmentId,
28872864
rootFormatContext: request.rootFormatContext,
28882865
progressiveChunkSize: request.progressiveChunkSize,
28892866
resumableState: request.resumableState,
2890-
resumablePath: root,
2867+
resumablePath: trackedPostpones.root,
28912868
};
28922869
}

0 commit comments

Comments
 (0)