Skip to content

Commit

Permalink
Remove Scheduler indirection
Browse files Browse the repository at this point in the history
I originally kept the React PriorityLevel and Scheduler PriorityLevel
types separate in case there was a versioning mismatch between the two
modules. However, it looks like we're going to keep the Scheduler module
private in the short to medium term, and longer term the public
interface will match postTask. So, I've removed the extra indirection
(the switch statements that convert between the two types).
  • Loading branch information
acdlite committed Mar 26, 2021
1 parent 191ae23 commit 8b0532a
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 201 deletions.
13 changes: 12 additions & 1 deletion packages/react-devtools-shared/src/backend/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export function getInternalReactConstants(
// Technically these priority levels are invalid for versions before 16.9,
// but 16.9 is the first version to report priority level to DevTools,
// so we can avoid checking for earlier versions and support pre-16.9 canary releases in the process.
const ReactPriorityLevels: ReactPriorityLevelsType = {
let ReactPriorityLevels: ReactPriorityLevelsType = {
ImmediatePriority: 99,
UserBlockingPriority: 98,
NormalPriority: 97,
Expand All @@ -168,6 +168,17 @@ export function getInternalReactConstants(
NoPriority: 90,
};

if (gte(version, '17.0.2-alpha')) {
ReactPriorityLevels = {
ImmediatePriority: 1,
UserBlockingPriority: 2,
NormalPriority: 3,
LowPriority: 4,
IdlePriority: 5,
NoPriority: 0,
};
}

let ReactTypeOfWork: WorkTagMap = ((null: any): WorkTagMap);

// **********************************************************
Expand Down
2 changes: 0 additions & 2 deletions packages/react-reconciler/src/ReactFiberHooks.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import type {
import type {Fiber, Dispatcher, HookType} from './ReactInternalTypes';
import type {Lanes, Lane} from './ReactFiberLane.new';
import type {HookFlags} from './ReactHookEffectTags';
import type {ReactPriorityLevel} from './ReactInternalTypes';
import type {FiberRoot} from './ReactInternalTypes';
import type {OpaqueIDType} from './ReactFiberHostConfig';
import type {Cache} from './ReactFiberCacheComponent.new';
Expand Down Expand Up @@ -120,7 +119,6 @@ type Update<S, A> = {|
eagerReducer: ((S, A) => S) | null,
eagerState: S | null,
next: Update<S, A>,
priority?: ReactPriorityLevel,
|};

export type UpdateQueue<S, A> = {|
Expand Down
2 changes: 0 additions & 2 deletions packages/react-reconciler/src/ReactFiberHooks.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import type {
import type {Fiber, Dispatcher, HookType} from './ReactInternalTypes';
import type {Lanes, Lane} from './ReactFiberLane.old';
import type {HookFlags} from './ReactHookEffectTags';
import type {ReactPriorityLevel} from './ReactInternalTypes';
import type {FiberRoot} from './ReactInternalTypes';
import type {OpaqueIDType} from './ReactFiberHostConfig';
import type {Cache} from './ReactFiberCacheComponent.old';
Expand Down Expand Up @@ -120,7 +119,6 @@ type Update<S, A> = {|
eagerReducer: ((S, A) => S) | null,
eagerState: S | null,
next: Update<S, A>,
priority?: ReactPriorityLevel,
|};

export type UpdateQueue<S, A> = {|
Expand Down
2 changes: 0 additions & 2 deletions packages/react-reconciler/src/ReactInternalTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ export type HookType =
| 'useOpaqueIdentifier'
| 'useCacheRefresh';

export type ReactPriorityLevel = 99 | 98 | 97 | 96 | 95 | 90;

export type ContextDependency<T> = {
context: ReactContext<T>,
next: ContextDependency<mixed> | null,
Expand Down
115 changes: 18 additions & 97 deletions packages/react-reconciler/src/SchedulerWithReactIntegration.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
* @flow
*/

import type {ReactPriorityLevel} from './ReactInternalTypes';

// Intentionally not named imports because Rollup would use dynamic dispatch for
// CommonJS interop named imports.
// This module only exists as an ESM wrapper around the external CommonJS
// Scheduler dependency. Notice that we're intentionally not using named imports
// because Rollup would use dynamic dispatch for CommonJS interop named imports.
// When we switch to ESM, we can delete this module.
import * as Scheduler from 'scheduler';
import {__interactionsRef} from 'scheduler/tracing';
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
Expand All @@ -21,19 +21,18 @@ import {
setCurrentUpdatePriority,
} from './ReactEventPriorities.new';

const {
unstable_scheduleCallback: Scheduler_scheduleCallback,
unstable_cancelCallback: Scheduler_cancelCallback,
unstable_shouldYield: Scheduler_shouldYield,
unstable_requestPaint: Scheduler_requestPaint,
unstable_now: Scheduler_now,
unstable_getCurrentPriorityLevel: Scheduler_getCurrentPriorityLevel,
unstable_ImmediatePriority: Scheduler_ImmediatePriority,
unstable_UserBlockingPriority: Scheduler_UserBlockingPriority,
unstable_NormalPriority: Scheduler_NormalPriority,
unstable_LowPriority: Scheduler_LowPriority,
unstable_IdlePriority: Scheduler_IdlePriority,
} = Scheduler;
export const scheduleCallback = Scheduler.unstable_scheduleCallback;
export const cancelCallback = Scheduler.unstable_cancelCallback;
export const shouldYield = Scheduler.unstable_shouldYield;
export const requestPaint = Scheduler.unstable_requestPaint;
export const now = Scheduler.unstable_now;
export const getCurrentPriorityLevel =
Scheduler.unstable_getCurrentPriorityLevel;
export const ImmediatePriority = Scheduler.unstable_ImmediatePriority;
export const UserBlockingPriority = Scheduler.unstable_UserBlockingPriority;
export const NormalPriority = Scheduler.unstable_NormalPriority;
export const LowPriority = Scheduler.unstable_LowPriority;
export const IdlePriority = Scheduler.unstable_IdlePriority;

if (enableSchedulerTracing) {
// Provide explicit error message when production+profiling bundle of e.g.
Expand All @@ -51,80 +50,9 @@ if (enableSchedulerTracing) {

export type SchedulerCallback = (isSync: boolean) => SchedulerCallback | null;

type SchedulerCallbackOptions = {timeout?: number, ...};

// Except for NoPriority, these correspond to Scheduler priorities. We use
// ascending numbers so we can compare them like numbers. They start at 90 to
// avoid clashing with Scheduler's priorities.
export const ImmediatePriority: ReactPriorityLevel = 99;
export const UserBlockingPriority: ReactPriorityLevel = 98;
export const NormalPriority: ReactPriorityLevel = 97;
export const LowPriority: ReactPriorityLevel = 96;
export const IdlePriority: ReactPriorityLevel = 95;
// NoPriority is the absence of priority. Also React-only.
export const NoPriority: ReactPriorityLevel = 90;

export const shouldYield = Scheduler_shouldYield;
export const requestPaint =
// Fall back gracefully if we're running an older version of Scheduler.
Scheduler_requestPaint !== undefined ? Scheduler_requestPaint : () => {};

// TODO: Move sync task queue to its own module.
let syncQueue: Array<SchedulerCallback> | null = null;
let isFlushingSyncQueue: boolean = false;
const initialTimeMs: number = Scheduler_now();

// If the initial timestamp is reasonably small, use Scheduler's `now` directly.
// This will be the case for modern browsers that support `performance.now`. In
// older browsers, Scheduler falls back to `Date.now`, which returns a Unix
// timestamp. In that case, subtract the module initialization time to simulate
// the behavior of performance.now and keep our times small enough to fit
// within 32 bits.
// TODO: Consider lifting this into Scheduler.
export const now =
initialTimeMs < 10000 ? Scheduler_now : () => Scheduler_now() - initialTimeMs;

export function getCurrentPriorityLevel(): ReactPriorityLevel {
switch (Scheduler_getCurrentPriorityLevel()) {
case Scheduler_ImmediatePriority:
return ImmediatePriority;
case Scheduler_UserBlockingPriority:
return UserBlockingPriority;
case Scheduler_NormalPriority:
return NormalPriority;
case Scheduler_LowPriority:
return LowPriority;
case Scheduler_IdlePriority:
return IdlePriority;
default:
invariant(false, 'Unknown priority level.');
}
}

function reactPriorityToSchedulerPriority(reactPriorityLevel) {
switch (reactPriorityLevel) {
case ImmediatePriority:
return Scheduler_ImmediatePriority;
case UserBlockingPriority:
return Scheduler_UserBlockingPriority;
case NormalPriority:
return Scheduler_NormalPriority;
case LowPriority:
return Scheduler_LowPriority;
case IdlePriority:
return Scheduler_IdlePriority;
default:
invariant(false, 'Unknown priority level.');
}
}

export function scheduleCallback(
reactPriorityLevel: ReactPriorityLevel,
callback: SchedulerCallback,
options: SchedulerCallbackOptions | void | null,
) {
const priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel);
return Scheduler_scheduleCallback(priorityLevel, callback, options);
}

export function scheduleSyncCallback(callback: SchedulerCallback) {
// Push this callback into an internal queue. We'll flush these either in
Expand All @@ -138,10 +66,6 @@ export function scheduleSyncCallback(callback: SchedulerCallback) {
}
}

export function cancelCallback(callbackNode: mixed) {
Scheduler_cancelCallback(callbackNode);
}

export function flushSyncCallbackQueue() {
if (!isFlushingSyncQueue && syncQueue !== null) {
// Prevent re-entrancy.
Expand All @@ -167,10 +91,7 @@ export function flushSyncCallbackQueue() {
syncQueue = syncQueue.slice(i + 1);
}
// Resume flushing in the next tick
Scheduler_scheduleCallback(
Scheduler_ImmediatePriority,
flushSyncCallbackQueue,
);
scheduleCallback(ImmediatePriority, flushSyncCallbackQueue);
throw error;
} finally {
setCurrentUpdatePriority(previousUpdatePriority);
Expand Down
115 changes: 18 additions & 97 deletions packages/react-reconciler/src/SchedulerWithReactIntegration.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
* @flow
*/

import type {ReactPriorityLevel} from './ReactInternalTypes';

// Intentionally not named imports because Rollup would use dynamic dispatch for
// CommonJS interop named imports.
// This module only exists as an ESM wrapper around the external CommonJS
// Scheduler dependency. Notice that we're intentionally not using named imports
// because Rollup would use dynamic dispatch for CommonJS interop named imports.
// When we switch to ESM, we can delete this module.
import * as Scheduler from 'scheduler';
import {__interactionsRef} from 'scheduler/tracing';
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
Expand All @@ -21,19 +21,18 @@ import {
setCurrentUpdatePriority,
} from './ReactEventPriorities.old';

const {
unstable_scheduleCallback: Scheduler_scheduleCallback,
unstable_cancelCallback: Scheduler_cancelCallback,
unstable_shouldYield: Scheduler_shouldYield,
unstable_requestPaint: Scheduler_requestPaint,
unstable_now: Scheduler_now,
unstable_getCurrentPriorityLevel: Scheduler_getCurrentPriorityLevel,
unstable_ImmediatePriority: Scheduler_ImmediatePriority,
unstable_UserBlockingPriority: Scheduler_UserBlockingPriority,
unstable_NormalPriority: Scheduler_NormalPriority,
unstable_LowPriority: Scheduler_LowPriority,
unstable_IdlePriority: Scheduler_IdlePriority,
} = Scheduler;
export const scheduleCallback = Scheduler.unstable_scheduleCallback;
export const cancelCallback = Scheduler.unstable_cancelCallback;
export const shouldYield = Scheduler.unstable_shouldYield;
export const requestPaint = Scheduler.unstable_requestPaint;
export const now = Scheduler.unstable_now;
export const getCurrentPriorityLevel =
Scheduler.unstable_getCurrentPriorityLevel;
export const ImmediatePriority = Scheduler.unstable_ImmediatePriority;
export const UserBlockingPriority = Scheduler.unstable_UserBlockingPriority;
export const NormalPriority = Scheduler.unstable_NormalPriority;
export const LowPriority = Scheduler.unstable_LowPriority;
export const IdlePriority = Scheduler.unstable_IdlePriority;

if (enableSchedulerTracing) {
// Provide explicit error message when production+profiling bundle of e.g.
Expand All @@ -51,80 +50,9 @@ if (enableSchedulerTracing) {

export type SchedulerCallback = (isSync: boolean) => SchedulerCallback | null;

type SchedulerCallbackOptions = {timeout?: number, ...};

// Except for NoPriority, these correspond to Scheduler priorities. We use
// ascending numbers so we can compare them like numbers. They start at 90 to
// avoid clashing with Scheduler's priorities.
export const ImmediatePriority: ReactPriorityLevel = 99;
export const UserBlockingPriority: ReactPriorityLevel = 98;
export const NormalPriority: ReactPriorityLevel = 97;
export const LowPriority: ReactPriorityLevel = 96;
export const IdlePriority: ReactPriorityLevel = 95;
// NoPriority is the absence of priority. Also React-only.
export const NoPriority: ReactPriorityLevel = 90;

export const shouldYield = Scheduler_shouldYield;
export const requestPaint =
// Fall back gracefully if we're running an older version of Scheduler.
Scheduler_requestPaint !== undefined ? Scheduler_requestPaint : () => {};

// TODO: Move sync task queue to its own module.
let syncQueue: Array<SchedulerCallback> | null = null;
let isFlushingSyncQueue: boolean = false;
const initialTimeMs: number = Scheduler_now();

// If the initial timestamp is reasonably small, use Scheduler's `now` directly.
// This will be the case for modern browsers that support `performance.now`. In
// older browsers, Scheduler falls back to `Date.now`, which returns a Unix
// timestamp. In that case, subtract the module initialization time to simulate
// the behavior of performance.now and keep our times small enough to fit
// within 32 bits.
// TODO: Consider lifting this into Scheduler.
export const now =
initialTimeMs < 10000 ? Scheduler_now : () => Scheduler_now() - initialTimeMs;

export function getCurrentPriorityLevel(): ReactPriorityLevel {
switch (Scheduler_getCurrentPriorityLevel()) {
case Scheduler_ImmediatePriority:
return ImmediatePriority;
case Scheduler_UserBlockingPriority:
return UserBlockingPriority;
case Scheduler_NormalPriority:
return NormalPriority;
case Scheduler_LowPriority:
return LowPriority;
case Scheduler_IdlePriority:
return IdlePriority;
default:
invariant(false, 'Unknown priority level.');
}
}

function reactPriorityToSchedulerPriority(reactPriorityLevel) {
switch (reactPriorityLevel) {
case ImmediatePriority:
return Scheduler_ImmediatePriority;
case UserBlockingPriority:
return Scheduler_UserBlockingPriority;
case NormalPriority:
return Scheduler_NormalPriority;
case LowPriority:
return Scheduler_LowPriority;
case IdlePriority:
return Scheduler_IdlePriority;
default:
invariant(false, 'Unknown priority level.');
}
}

export function scheduleCallback(
reactPriorityLevel: ReactPriorityLevel,
callback: SchedulerCallback,
options: SchedulerCallbackOptions | void | null,
) {
const priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel);
return Scheduler_scheduleCallback(priorityLevel, callback, options);
}

export function scheduleSyncCallback(callback: SchedulerCallback) {
// Push this callback into an internal queue. We'll flush these either in
Expand All @@ -138,10 +66,6 @@ export function scheduleSyncCallback(callback: SchedulerCallback) {
}
}

export function cancelCallback(callbackNode: mixed) {
Scheduler_cancelCallback(callbackNode);
}

export function flushSyncCallbackQueue() {
if (!isFlushingSyncQueue && syncQueue !== null) {
// Prevent re-entrancy.
Expand All @@ -167,10 +91,7 @@ export function flushSyncCallbackQueue() {
syncQueue = syncQueue.slice(i + 1);
}
// Resume flushing in the next tick
Scheduler_scheduleCallback(
Scheduler_ImmediatePriority,
flushSyncCallbackQueue,
);
scheduleCallback(ImmediatePriority, flushSyncCallbackQueue);
throw error;
} finally {
setCurrentUpdatePriority(previousUpdatePriority);
Expand Down

0 comments on commit 8b0532a

Please sign in to comment.