Skip to content

Commit 9b366ff

Browse files
committed
[Flight] Schedule work in a microtask
Flight pings much more often than Fizz because async function components will always take at least a microtask to resolve . Rather than scheduling this work as a new macrotask Flight now schedules pings in a microtask. This allows more microta sks to ping before actually doing a work flush but doesn't force the vm to sping up a new task which is quite common give n the nature of Server Components
1 parent 54bbd70 commit 9b366ff

11 files changed

+68
-1
lines changed

packages/react-dom-bindings/src/server/ReactDOMLegacyServerStreamConfig.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ export function scheduleWork(callback: () => void) {
2020
callback();
2121
}
2222

23+
export function scheduleMicrotask(callback: () => void) {
24+
// While this defies the method name the legacy builds have special
25+
// overrides that make work scheduling sync. At the moment scheduleMicrotask
26+
// isn't used by any legacy APIs so this is somewhat academic but if they
27+
// did in the future we'd probably want to have this be in sync with scheduleWork
28+
callback();
29+
}
30+
2331
export function flushBuffered(destination: Destination) {}
2432

2533
export function beginWriting(destination: Destination) {}

packages/react-noop-renderer/src/ReactNoopFlightServer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ type Destination = Array<Uint8Array>;
2525
const textEncoder = new TextEncoder();
2626

2727
const ReactNoopFlightServer = ReactFlightServer({
28+
scheduleMicrotask(callback: () => void) {
29+
callback();
30+
},
2831
scheduleWork(callback: () => void) {
2932
callback();
3033
},

packages/react-noop-renderer/src/ReactNoopServer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ function write(destination: Destination, buffer: Uint8Array): void {
7474
}
7575

7676
const ReactNoopServer = ReactFizzServer({
77+
scheduleMicrotask(callback: () => void) {
78+
callback();
79+
},
7780
scheduleWork(callback: () => void) {
7881
callback();
7982
},

packages/react-server/src/ReactFlightServer.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {enableFlightReadableStream} from 'shared/ReactFeatureFlags';
2626

2727
import {
2828
scheduleWork,
29+
scheduleMicrotask,
2930
flushBuffered,
3031
beginWriting,
3132
writeChunkAndReturn,
@@ -1514,7 +1515,7 @@ function pingTask(request: Request, task: Task): void {
15141515
pingedTasks.push(task);
15151516
if (pingedTasks.length === 1) {
15161517
request.flushScheduled = request.destination !== null;
1517-
scheduleWork(() => performWork(request));
1518+
scheduleMicrotask(() => performWork(request));
15181519
}
15191520
}
15201521

packages/react-server/src/ReactServerStreamConfigBrowser.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ export function scheduleWork(callback: () => void) {
2727
channel.port2.postMessage(null);
2828
}
2929

30+
function handleErrorInNextTick(error: any) {
31+
setTimeout(() => {
32+
throw error;
33+
});
34+
}
35+
36+
const LocalPromise = Promise;
37+
38+
export const scheduleMicrotask: (callback: () => void) => void =
39+
typeof queueMicrotask === 'function'
40+
? queueMicrotask
41+
: callback => {
42+
LocalPromise.resolve(null).then(callback).catch(handleErrorInNextTick);
43+
};
44+
3045
export function flushBuffered(destination: Destination) {
3146
// WHATWG Streams do not yet have a way to flush the underlying
3247
// transform streams. https://github.com/whatwg/streams/issues/960

packages/react-server/src/ReactServerStreamConfigBun.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export function scheduleWork(callback: () => void) {
2525
setTimeout(callback, 0);
2626
}
2727

28+
export const scheduleMicrotask = queueMicrotask;
29+
2830
export function flushBuffered(destination: Destination) {
2931
// Bun direct streams provide a flush function.
3032
// If we don't have any more data to send right now.

packages/react-server/src/ReactServerStreamConfigEdge.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ export type PrecomputedChunk = Uint8Array;
1313
export opaque type Chunk = Uint8Array;
1414
export type BinaryChunk = Uint8Array;
1515

16+
function handleErrorInNextTick(error: any) {
17+
setTimeout(() => {
18+
throw error;
19+
});
20+
}
21+
22+
const LocalPromise = Promise;
23+
24+
export const scheduleMicrotask: (callback: () => void) => void =
25+
typeof queueMicrotask === 'function'
26+
? queueMicrotask
27+
: callback => {
28+
LocalPromise.resolve(null).then(callback).catch(handleErrorInNextTick);
29+
};
30+
1631
export function scheduleWork(callback: () => void) {
1732
setTimeout(callback, 0);
1833
}

packages/react-server/src/ReactServerStreamConfigNode.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export function scheduleWork(callback: () => void) {
2626
setImmediate(callback);
2727
}
2828

29+
export const scheduleMicrotask = queueMicrotask;
30+
2931
export function flushBuffered(destination: Destination) {
3032
// If we don't have any more data to send right now.
3133
// Flush whatever is in the buffer to the wire.

packages/react-server/src/forks/ReactServerStreamConfig.custom.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export opaque type Chunk = mixed; // eslint-disable-line no-undef
3131
export opaque type BinaryChunk = mixed; // eslint-disable-line no-undef
3232

3333
export const scheduleWork = $$$config.scheduleWork;
34+
export const scheduleMicrotask = $$$config.scheduleMicrotask;
3435
export const beginWriting = $$$config.beginWriting;
3536
export const writeChunk = $$$config.writeChunk;
3637
export const writeChunkAndReturn = $$$config.writeChunkAndReturn;

packages/react-server/src/forks/ReactServerStreamConfig.dom-fb-experimental.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ export interface Destination {
4242
onError(error: mixed): void;
4343
}
4444

45+
function handleErrorInNextTick(error: any) {
46+
setTimeout(() => {
47+
throw error;
48+
});
49+
}
50+
51+
export const scheduleMicrotask: (callback: () => void) => void =
52+
typeof queueMicrotask === 'function'
53+
? queueMicrotask
54+
: callback => {
55+
Promise.resolve(null).then(callback).catch(handleErrorInNextTick);
56+
};
57+
4558
export function scheduleWork(callback: () => void) {
4659
setTimeout(callback, 0);
4760
}

0 commit comments

Comments
 (0)