Move sync task queue to its own module (#21109)
The sync task queue is React-specific and doesn't really have anything to do with Scheduler. We'd keep using it even once `postTask` exists. By separating that part out, `SchedulerWithReactIntegration` is now just a module that re-exports the Scheduler API. So I unforked it. When we switch to ES Modules, we can remove this re-exporting module.
Andrew Clark committed
Mar 28, 2021 at 16:15 UTC
dbe98a5aae79efce4de3eea95171d1ef70537fdb
10 files changed
+84
-112
packages/react-dom/src/events/ReactDOMEventListener.js
+4
-12
@@ -34,25 +34,21 @@ import {
34
import getEventTarget from './getEventTarget';
35
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
36
37
-import {
38
- enableLegacyFBSupport,
39
- enableNewReconciler,
40
-} from 'shared/ReactFeatureFlags';
37
+import {enableLegacyFBSupport} from 'shared/ReactFeatureFlags';
38
import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem';
39
import {
40
flushDiscreteUpdatesIfNeeded,
41
discreteUpdates,
42
} from './ReactDOMUpdateBatching';
43
47
-import {getCurrentPriorityLevel as getCurrentPriorityLevel_old} from 'react-reconciler/src/SchedulerWithReactIntegration.old';
44
import {
49
- getCurrentPriorityLevel as getCurrentPriorityLevel_new,
45
+ getCurrentPriorityLevel as getCurrentSchedulerPriorityLevel,
46
IdlePriority as IdleSchedulerPriority,
47
ImmediatePriority as ImmediateSchedulerPriority,
48
LowPriority as LowSchedulerPriority,
49
NormalPriority as NormalSchedulerPriority,
50
UserBlockingPriority as UserBlockingSchedulerPriority,
55
-} from 'react-reconciler/src/SchedulerWithReactIntegration.new';
51
+} from 'react-reconciler/src/Scheduler';
52
import {
53
DiscreteEventPriority,
54
ContinuousEventPriority,
@@ -62,10 +58,6 @@ import {
58
setCurrentUpdatePriority,
59
} from 'react-reconciler/src/ReactEventPriorities';
60
65
-const getCurrentPriorityLevel = enableNewReconciler
66
- ? getCurrentPriorityLevel_new
67
- : getCurrentPriorityLevel_old;
68
-
61
// TODO: can we stop exporting these?
62
export let _enabled = true;
63
@@ -392,7 +384,7 @@ export function getEventPriority(domEventName: DOMEventName): * {
384
// We might be in the Scheduler callback.
385
// Eventually this mechanism will be replaced by a check
386
// of the current priority on the native scheduler.
395
- const schedulerPriority = getCurrentPriorityLevel();
387
+ const schedulerPriority = getCurrentSchedulerPriorityLevel();
388
switch (schedulerPriority) {
389
case ImmediateSchedulerPriority:
390
return DiscreteEventPriority;
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+1
-1
@@ -28,7 +28,7 @@ import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.new';
28
29
import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.new';
30
31
-import {now} from './SchedulerWithReactIntegration.new';
31
+import {now} from './Scheduler';
32
33
import {
34
IndeterminateComponent,
packages/react-reconciler/src/ReactFiberCompleteWork.old.js
+1
-1
@@ -28,7 +28,7 @@ import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.old';
28
29
import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.old';
30
31
-import {now} from './SchedulerWithReactIntegration.old';
31
+import {now} from './Scheduler';
32
33
import {
34
IndeterminateComponent,
packages/react-reconciler/src/ReactFiberDevToolsHook.new.js
+1
-1
@@ -25,7 +25,7 @@ import {
25
UserBlockingPriority as UserBlockingSchedulerPriority,
26
NormalPriority as NormalSchedulerPriority,
27
IdlePriority as IdleSchedulerPriority,
28
-} from './SchedulerWithReactIntegration.new';
28
+} from './Scheduler';
29
30
declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: Object | void;
31
packages/react-reconciler/src/ReactFiberDevToolsHook.old.js
+1
-1
@@ -25,7 +25,7 @@ import {
25
UserBlockingPriority as UserBlockingSchedulerPriority,
26
NormalPriority as NormalSchedulerPriority,
27
IdlePriority as IdleSchedulerPriority,
28
-} from './SchedulerWithReactIntegration.old';
28
+} from './Scheduler';
29
30
declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: Object | void;
31
packages/react-reconciler/src/ReactFiberSyncTaskQueue.new.js
new
+67
@@ -0,0 +1,67 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ */
9
+
10
+import type {SchedulerCallback} from './Scheduler';
11
+
12
+import {
13
+ DiscreteEventPriority,
14
+ getCurrentUpdatePriority,
15
+ setCurrentUpdatePriority,
16
+} from './ReactEventPriorities.new';
17
+import {ImmediatePriority, scheduleCallback} from './Scheduler';
18
+
19
+let syncQueue: Array<SchedulerCallback> | null = null;
20
+let isFlushingSyncQueue: boolean = false;
21
+
22
+export function scheduleSyncCallback(callback: SchedulerCallback) {
23
+ // Push this callback into an internal queue. We'll flush these either in
24
+ // the next tick, or earlier if something calls `flushSyncCallbackQueue`.
25
+ if (syncQueue === null) {
26
+ syncQueue = [callback];
27
+ } else {
28
+ // Push onto existing queue. Don't need to schedule a callback because
29
+ // we already scheduled one when we created the queue.
30
+ syncQueue.push(callback);
31
+ }
32
+}
33
+
34
+export function flushSyncCallbackQueue() {
35
+ if (!isFlushingSyncQueue && syncQueue !== null) {
36
+ // Prevent re-entrancy.
37
+ isFlushingSyncQueue = true;
38
+ let i = 0;
39
+ const previousUpdatePriority = getCurrentUpdatePriority();
40
+ try {
41
+ const isSync = true;
42
+ const queue = syncQueue;
43
+ // TODO: Is this necessary anymore? The only user code that runs in this
44
+ // queue is in the render or commit phases.
45
+ setCurrentUpdatePriority(DiscreteEventPriority);
46
+ for (; i < queue.length; i++) {
47
+ let callback = queue[i];
48
+ do {
49
+ callback = callback(isSync);
50
+ } while (callback !== null);
51
+ }
52
+ syncQueue = null;
53
+ } catch (error) {
54
+ // If something throws, leave the remaining callbacks on the queue.
55
+ if (syncQueue !== null) {
56
+ syncQueue = syncQueue.slice(i + 1);
57
+ }
58
+ // Resume flushing in the next tick
59
+ scheduleCallback(ImmediatePriority, flushSyncCallbackQueue);
60
+ throw error;
61
+ } finally {
62
+ setCurrentUpdatePriority(previousUpdatePriority);
63
+ isFlushingSyncQueue = false;
64
+ }
65
+ }
66
+ return null;
67
+}
packages/react-reconciler/src/ReactFiberSyncTaskQueue.old.js
renamed
+3
-38
@@ -7,50 +7,15 @@
7
* @flow
8
*/
9
10
-// This module only exists as an ESM wrapper around the external CommonJS
11
-// Scheduler dependency. Notice that we're intentionally not using named imports
12
-// because Rollup would use dynamic dispatch for CommonJS interop named imports.
13
-// When we switch to ESM, we can delete this module.
14
-import * as Scheduler from 'scheduler';
15
-import {__interactionsRef} from 'scheduler/tracing';
16
-import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
17
-import invariant from 'shared/invariant';
10
+import type {SchedulerCallback} from './Scheduler';
11
+
12
import {
13
DiscreteEventPriority,
14
getCurrentUpdatePriority,
15
setCurrentUpdatePriority,
16
} from './ReactEventPriorities.old';
17
+import {ImmediatePriority, scheduleCallback} from './Scheduler';
18
24
-export const scheduleCallback = Scheduler.unstable_scheduleCallback;
25
-export const cancelCallback = Scheduler.unstable_cancelCallback;
26
-export const shouldYield = Scheduler.unstable_shouldYield;
27
-export const requestPaint = Scheduler.unstable_requestPaint;
28
-export const now = Scheduler.unstable_now;
29
-export const getCurrentPriorityLevel =
30
- Scheduler.unstable_getCurrentPriorityLevel;
31
-export const ImmediatePriority = Scheduler.unstable_ImmediatePriority;
32
-export const UserBlockingPriority = Scheduler.unstable_UserBlockingPriority;
33
-export const NormalPriority = Scheduler.unstable_NormalPriority;
34
-export const LowPriority = Scheduler.unstable_LowPriority;
35
-export const IdlePriority = Scheduler.unstable_IdlePriority;
36
-
37
-if (enableSchedulerTracing) {
38
- // Provide explicit error message when production+profiling bundle of e.g.
39
- // react-dom is used with production (non-profiling) bundle of
40
- // scheduler/tracing
41
- invariant(
42
- __interactionsRef != null && __interactionsRef.current != null,
43
- 'It is not supported to run the profiling version of a renderer (for ' +
44
- 'example, `react-dom/profiling`) without also replacing the ' +
45
- '`scheduler/tracing` module with `scheduler/tracing-profiling`. Your ' +
46
- 'bundler might have a setting for aliasing both modules. Learn more at ' +
47
- 'https://reactjs.org/link/profiling',
48
- );
49
-}
50
-
51
-export type SchedulerCallback = (isSync: boolean) => SchedulerCallback | null;
52
-
53
-// TODO: Move sync task queue to its own module.
19
let syncQueue: Array<SchedulerCallback> | null = null;
20
let isFlushingSyncQueue: boolean = false;
21
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+3
-1
@@ -46,9 +46,11 @@ import {
46
UserBlockingPriority as UserBlockingSchedulerPriority,
47
NormalPriority as NormalSchedulerPriority,
48
IdlePriority as IdleSchedulerPriority,
49
+} from './Scheduler';
50
+import {
51
flushSyncCallbackQueue,
52
scheduleSyncCallback,
51
-} from './SchedulerWithReactIntegration.new';
53
+} from './ReactFiberSyncTaskQueue.new';
54
import {
55
NoFlags as NoHookEffect,
56
Passive as HookPassive,
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+3
-1
@@ -46,9 +46,11 @@ import {
46
UserBlockingPriority as UserBlockingSchedulerPriority,
47
NormalPriority as NormalSchedulerPriority,
48
IdlePriority as IdleSchedulerPriority,
49
+} from './Scheduler';
50
+import {
51
flushSyncCallbackQueue,
52
scheduleSyncCallback,
51
-} from './SchedulerWithReactIntegration.old';
53
+} from './ReactFiberSyncTaskQueue.old';
54
import {
55
NoFlags as NoHookEffect,
56
Passive as HookPassive,
packages/react-reconciler/src/Scheduler.js
renamed
-56
@@ -15,11 +15,6 @@ import * as Scheduler from 'scheduler';
15
import {__interactionsRef} from 'scheduler/tracing';
16
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
17
import invariant from 'shared/invariant';
18
-import {
19
- DiscreteEventPriority,
20
- getCurrentUpdatePriority,
21
- setCurrentUpdatePriority,
22
-} from './ReactEventPriorities.new';
18
19
export const scheduleCallback = Scheduler.unstable_scheduleCallback;
20
export const cancelCallback = Scheduler.unstable_cancelCallback;
@@ -49,54 +44,3 @@ if (enableSchedulerTracing) {
44
}
45
46
export type SchedulerCallback = (isSync: boolean) => SchedulerCallback | null;
52
-
53
-// TODO: Move sync task queue to its own module.
54
-let syncQueue: Array<SchedulerCallback> | null = null;
55
-let isFlushingSyncQueue: boolean = false;
56
-
57
-export function scheduleSyncCallback(callback: SchedulerCallback) {
58
- // Push this callback into an internal queue. We'll flush these either in
59
- // the next tick, or earlier if something calls `flushSyncCallbackQueue`.
60
- if (syncQueue === null) {
61
- syncQueue = [callback];
62
- } else {
63
- // Push onto existing queue. Don't need to schedule a callback because
64
- // we already scheduled one when we created the queue.
65
- syncQueue.push(callback);
66
- }
67
-}
68
-
69
-export function flushSyncCallbackQueue() {
70
- if (!isFlushingSyncQueue && syncQueue !== null) {
71
- // Prevent re-entrancy.
72
- isFlushingSyncQueue = true;
73
- let i = 0;
74
- const previousUpdatePriority = getCurrentUpdatePriority();
75
- try {
76
- const isSync = true;
77
- const queue = syncQueue;
78
- // TODO: Is this necessary anymore? The only user code that runs in this
79
- // queue is in the render or commit phases.
80
- setCurrentUpdatePriority(DiscreteEventPriority);
81
- for (; i < queue.length; i++) {
82
- let callback = queue[i];
83
- do {
84
- callback = callback(isSync);
85
- } while (callback !== null);
86
- }
87
- syncQueue = null;
88
- } catch (error) {
89
- // If something throws, leave the remaining callbacks on the queue.
90
- if (syncQueue !== null) {
91
- syncQueue = syncQueue.slice(i + 1);
92
- }
93
- // Resume flushing in the next tick
94
- scheduleCallback(ImmediatePriority, flushSyncCallbackQueue);
95
- throw error;
96
- } finally {
97
- setCurrentUpdatePriority(previousUpdatePriority);
98
- isFlushingSyncQueue = false;
99
- }
100
- }
101
- return null;
102
-}