From d8e49f2af84c810457eb81ac7fe68fd0fdece859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 8 Mar 2023 15:34:29 -0500 Subject: [PATCH] Use setTimeout to schedule work on the server in Edge environments (#26348) We rely heavily on being able to batch rendering after multiple fetches etc. have completed on the server. However, we only do this in the Node.js build. Node.js `setImmediate` has the exact semantics we need. To be after the current cycle of I/O so that we can collect after all those I/O events already in the queue has been processed. This doesn't exist in standard browsers, so we ended up not using it there. We could've used `setTimeout` but that risks being throttled which would severely negatively affect the performance so we just did it synchronously there. We probably could just use the `scheduler` there. Now we have a separate build for Edge where `setTimeout(..., 0)` actually behaves like `setImmediate` which is what we want. So we can just use that in that build. @Jarred-Sumner not sure what you want for Bun. --- .../src/__tests__/ReactFlightDOMEdge-test.js | 4 ++++ packages/react-server/src/ReactServerStreamConfigEdge.js | 2 +- packages/react/src/__tests__/ReactFetchEdge-test.js | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index 4cba5aa91405b..d08aafbcf2a19 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -15,6 +15,10 @@ global.ReadableStream = global.TextEncoder = require('util').TextEncoder; global.TextDecoder = require('util').TextDecoder; +// Don't wait before processing work on the server. +// TODO: we can replace this with FlightServer.act(). +global.setTimeout = cb => cb(); + let clientExports; let webpackMap; let webpackModules; diff --git a/packages/react-server/src/ReactServerStreamConfigEdge.js b/packages/react-server/src/ReactServerStreamConfigEdge.js index a898e6b8d40fe..d4157623e452d 100644 --- a/packages/react-server/src/ReactServerStreamConfigEdge.js +++ b/packages/react-server/src/ReactServerStreamConfigEdge.js @@ -13,7 +13,7 @@ export type PrecomputedChunk = Uint8Array; export opaque type Chunk = Uint8Array; export function scheduleWork(callback: () => void) { - callback(); + setTimeout(callback, 0); } export function flushBuffered(destination: Destination) { diff --git a/packages/react/src/__tests__/ReactFetchEdge-test.js b/packages/react/src/__tests__/ReactFetchEdge-test.js index 10484b853bf50..832b8e542843e 100644 --- a/packages/react/src/__tests__/ReactFetchEdge-test.js +++ b/packages/react/src/__tests__/ReactFetchEdge-test.js @@ -20,6 +20,10 @@ global.Response = require('node-fetch').Response; // Patch for Edge environments for global scope global.AsyncLocalStorage = require('async_hooks').AsyncLocalStorage; +// Don't wait before processing work on the server. +// TODO: we can replace this with FlightServer.act(). +global.setTimeout = cb => cb(); + let fetchCount = 0; async function fetchMock(resource, options) { fetchCount++;