Skip to content

Commit 1f062b4

Browse files
committed
[Flight][Fizz] schedule work async
While most builds of Flight and Fizz schedule work in new tasks some do execute work synchronously. While this is necessary for legacy APIs like renderToString for modern APIs there really isn't a great reason to do this synchronously. This change updates all non-legacy uses to be async using the best availalble scheduler at runtime
1 parent def67b9 commit 1f062b4

22 files changed

+1419
-837
lines changed

packages/react-dom/src/__tests__/ReactClassComponentPropResolutionFizz-test.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
'use strict';
1111

1212
import {insertNodesAndExecuteScripts} from '../test-utils/FizzTestUtils';
13+
import {patchMessageChannel} from '../../../../scripts/jest/patchMessageChannel';
1314

1415
// Polyfills for test environment
1516
global.ReadableStream =
@@ -21,12 +22,16 @@ let ReactDOMServer;
2122
let Scheduler;
2223
let assertLog;
2324
let container;
25+
let act;
2426

2527
describe('ReactClassComponentPropResolutionFizz', () => {
2628
beforeEach(() => {
2729
jest.resetModules();
28-
React = require('react');
2930
Scheduler = require('scheduler');
31+
patchMessageChannel(Scheduler);
32+
act = require('internal-test-utils').act;
33+
34+
React = require('react');
3035
ReactDOMServer = require('react-dom/server.browser');
3136
assertLog = require('internal-test-utils').assertLog;
3237
container = document.createElement('div');
@@ -37,6 +42,17 @@ describe('ReactClassComponentPropResolutionFizz', () => {
3742
document.body.removeChild(container);
3843
});
3944

45+
async function serverAct(callback) {
46+
let maybePromise;
47+
await act(() => {
48+
maybePromise = callback();
49+
if (maybePromise && typeof maybePromise.catch === 'function') {
50+
maybePromise.catch(() => {});
51+
}
52+
});
53+
return maybePromise;
54+
}
55+
4056
async function readIntoContainer(stream) {
4157
const reader = stream.getReader();
4258
let result = '';
@@ -57,7 +73,7 @@ describe('ReactClassComponentPropResolutionFizz', () => {
5773
return text;
5874
}
5975

60-
test('resolves ref and default props before calling lifecycle methods', async () => {
76+
it('resolves ref and default props before calling lifecycle methods', async () => {
6177
function getPropKeys(props) {
6278
return Object.keys(props).join(', ');
6379
}
@@ -80,11 +96,13 @@ describe('ReactClassComponentPropResolutionFizz', () => {
8096
};
8197

8298
// `ref` should never appear as a prop. `default` always should.
99+
83100
const ref = React.createRef();
84-
const stream = await ReactDOMServer.renderToReadableStream(
85-
<Component text="Yay" ref={ref} />,
101+
const stream = await serverAct(() =>
102+
ReactDOMServer.renderToReadableStream(<Component text="Yay" ref={ref} />),
86103
);
87104
await readIntoContainer(stream);
105+
88106
assertLog([
89107
'constructor: text, default',
90108
'componentWillMount: text, default',

packages/react-dom/src/__tests__/ReactDOMFizzDeferredValue-test.js

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
insertNodesAndExecuteScripts,
1414
getVisibleChildren,
1515
} from '../test-utils/FizzTestUtils';
16+
import {patchMessageChannel} from '../../../../scripts/jest/patchMessageChannel';
1617

1718
// Polyfills for test environment
1819
global.ReadableStream =
@@ -33,13 +34,14 @@ let Suspense;
3334
describe('ReactDOMFizzForm', () => {
3435
beforeEach(() => {
3536
jest.resetModules();
36-
React = require('react');
3737
Scheduler = require('scheduler');
38+
patchMessageChannel(Scheduler);
39+
act = require('internal-test-utils').act;
40+
React = require('react');
3841
ReactDOMServer = require('react-dom/server.browser');
3942
ReactDOMClient = require('react-dom/client');
4043
useDeferredValue = React.useDeferredValue;
4144
Suspense = React.Suspense;
42-
act = require('internal-test-utils').act;
4345
assertLog = require('internal-test-utils').assertLog;
4446
waitForPaint = require('internal-test-utils').waitForPaint;
4547
container = document.createElement('div');
@@ -50,6 +52,17 @@ describe('ReactDOMFizzForm', () => {
5052
document.body.removeChild(container);
5153
});
5254

55+
async function serverAct(callback) {
56+
let maybePromise;
57+
await act(() => {
58+
maybePromise = callback();
59+
if (maybePromise && typeof maybePromise.catch === 'function') {
60+
maybePromise.catch(() => {});
61+
}
62+
});
63+
return maybePromise;
64+
}
65+
5366
async function readIntoContainer(stream) {
5467
const reader = stream.getReader();
5568
let result = '';
@@ -76,7 +89,9 @@ describe('ReactDOMFizzForm', () => {
7689
return useDeferredValue('Final', 'Initial');
7790
}
7891

79-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
92+
const stream = await serverAct(() =>
93+
ReactDOMServer.renderToReadableStream(<App />),
94+
);
8095
await readIntoContainer(stream);
8196
expect(container.textContent).toEqual('Initial');
8297

@@ -107,7 +122,9 @@ describe('ReactDOMFizzForm', () => {
107122
);
108123
}
109124

110-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
125+
const stream = await serverAct(() =>
126+
ReactDOMServer.renderToReadableStream(<App />),
127+
);
111128
await readIntoContainer(stream);
112129
expect(container.textContent).toEqual('Loading...');
113130

@@ -153,8 +170,9 @@ describe('ReactDOMFizzForm', () => {
153170

154171
const cRef = React.createRef();
155172

156-
// The server renders using the "initial" value for B.
157-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
173+
const stream = await serverAct(() =>
174+
ReactDOMServer.renderToReadableStream(<App />),
175+
);
158176
await readIntoContainer(stream);
159177
assertLog(['A', 'B [Initial]', 'C']);
160178
expect(getVisibleChildren(container)).toEqual(

packages/react-dom/src/__tests__/ReactDOMFizzForm-test.js

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
'use strict';
1111

1212
import {insertNodesAndExecuteScripts} from '../test-utils/FizzTestUtils';
13+
import {patchMessageChannel} from '../../../../scripts/jest/patchMessageChannel';
1314

1415
// Polyfills for test environment
1516
global.ReadableStream =
@@ -24,10 +25,13 @@ let ReactDOMClient;
2425
let useFormStatus;
2526
let useOptimistic;
2627
let useActionState;
28+
let Scheduler;
2729

2830
describe('ReactDOMFizzForm', () => {
2931
beforeEach(() => {
3032
jest.resetModules();
33+
Scheduler = require('scheduler');
34+
patchMessageChannel(Scheduler);
3135
React = require('react');
3236
ReactDOMServer = require('react-dom/server.browser');
3337
ReactDOMClient = require('react-dom/client');
@@ -48,6 +52,14 @@ describe('ReactDOMFizzForm', () => {
4852
document.body.removeChild(container);
4953
});
5054

55+
async function serverAct(callback) {
56+
let maybePromise;
57+
await act(() => {
58+
maybePromise = callback();
59+
});
60+
return maybePromise;
61+
}
62+
5163
function submit(submitter) {
5264
const form = submitter.form || submitter;
5365
if (!submitter.form) {
@@ -96,7 +108,9 @@ describe('ReactDOMFizzForm', () => {
96108
);
97109
}
98110

99-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
111+
const stream = await serverAct(() =>
112+
ReactDOMServer.renderToReadableStream(<App />),
113+
);
100114
await readIntoContainer(stream);
101115
await act(async () => {
102116
ReactDOMClient.hydrateRoot(container, <App />);
@@ -143,7 +157,9 @@ describe('ReactDOMFizzForm', () => {
143157
);
144158
}
145159

146-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
160+
const stream = await serverAct(() =>
161+
ReactDOMServer.renderToReadableStream(<App />),
162+
);
147163
await readIntoContainer(stream);
148164
await act(async () => {
149165
ReactDOMClient.hydrateRoot(container, <App />);
@@ -175,7 +191,9 @@ describe('ReactDOMFizzForm', () => {
175191
);
176192
}
177193

178-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
194+
const stream = await serverAct(() =>
195+
ReactDOMServer.renderToReadableStream(<App />),
196+
);
179197
await readIntoContainer(stream);
180198
await expect(async () => {
181199
await act(async () => {
@@ -197,7 +215,9 @@ describe('ReactDOMFizzForm', () => {
197215
);
198216
}
199217

200-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
218+
const stream = await serverAct(() =>
219+
ReactDOMServer.renderToReadableStream(<App />),
220+
);
201221
await readIntoContainer(stream);
202222
// This should ideally warn because only the client provides a function that doesn't line up.
203223
await act(async () => {
@@ -231,7 +251,9 @@ describe('ReactDOMFizzForm', () => {
231251
);
232252
}
233253

234-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
254+
const stream = await serverAct(() =>
255+
ReactDOMServer.renderToReadableStream(<App />),
256+
);
235257
await readIntoContainer(stream);
236258
let root;
237259
await act(async () => {
@@ -278,7 +300,9 @@ describe('ReactDOMFizzForm', () => {
278300
);
279301
}
280302

281-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
303+
const stream = await serverAct(() =>
304+
ReactDOMServer.renderToReadableStream(<App />),
305+
);
282306
await readIntoContainer(stream);
283307
let root;
284308
await act(async () => {
@@ -334,7 +358,9 @@ describe('ReactDOMFizzForm', () => {
334358
// Specifying the extra form fields are a DEV error, but we expect it
335359
// to eventually still be patched up after an update.
336360
await expect(async () => {
337-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
361+
const stream = await serverAct(() =>
362+
ReactDOMServer.renderToReadableStream(<App />),
363+
);
338364
await readIntoContainer(stream);
339365
}).toErrorDev([
340366
'Cannot specify a encType or method for a form that specifies a function as the action.',
@@ -379,7 +405,9 @@ describe('ReactDOMFizzForm', () => {
379405
return 'Pending: ' + pending;
380406
}
381407

382-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
408+
const stream = await serverAct(() =>
409+
ReactDOMServer.renderToReadableStream(<App />),
410+
);
383411
await readIntoContainer(stream);
384412
expect(container.textContent).toBe('Pending: false');
385413

@@ -400,7 +428,9 @@ describe('ReactDOMFizzForm', () => {
400428
);
401429
}
402430

403-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
431+
const stream = await serverAct(() =>
432+
ReactDOMServer.renderToReadableStream(<App />),
433+
);
404434
await readIntoContainer(stream);
405435

406436
// Dispatch an event before hydration
@@ -441,7 +471,9 @@ describe('ReactDOMFizzForm', () => {
441471
);
442472
}
443473

444-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
474+
const stream = await serverAct(() =>
475+
ReactDOMServer.renderToReadableStream(<App />),
476+
);
445477
await readIntoContainer(stream);
446478

447479
submit(container.getElementsByTagName('input')[1]);
@@ -463,7 +495,9 @@ describe('ReactDOMFizzForm', () => {
463495
return optimisticState;
464496
}
465497

466-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
498+
const stream = await serverAct(() =>
499+
ReactDOMServer.renderToReadableStream(<App />),
500+
);
467501
await readIntoContainer(stream);
468502
expect(container.textContent).toBe('hi');
469503

@@ -484,7 +518,9 @@ describe('ReactDOMFizzForm', () => {
484518
return state;
485519
}
486520

487-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
521+
const stream = await serverAct(() =>
522+
ReactDOMServer.renderToReadableStream(<App />),
523+
);
488524
await readIntoContainer(stream);
489525
expect(container.textContent).toBe('0');
490526

@@ -521,7 +557,9 @@ describe('ReactDOMFizzForm', () => {
521557
);
522558
}
523559

524-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
560+
const stream = await serverAct(() =>
561+
ReactDOMServer.renderToReadableStream(<App />),
562+
);
525563
await readIntoContainer(stream);
526564

527565
const form = container.firstChild;
@@ -581,7 +619,9 @@ describe('ReactDOMFizzForm', () => {
581619
);
582620
}
583621

584-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
622+
const stream = await serverAct(() =>
623+
ReactDOMServer.renderToReadableStream(<App />),
624+
);
585625
await readIntoContainer(stream);
586626

587627
const input = container.getElementsByTagName('input')[1];
@@ -651,7 +691,9 @@ describe('ReactDOMFizzForm', () => {
651691
);
652692
}
653693

654-
const stream = await ReactDOMServer.renderToReadableStream(<App />);
694+
const stream = await serverAct(() =>
695+
ReactDOMServer.renderToReadableStream(<App />),
696+
);
655697
await readIntoContainer(stream);
656698

657699
const barField = container.querySelector('[name=bar]');

0 commit comments

Comments
 (0)