Skip to content

Commit

Permalink
Queue discrete events in microtask
Browse files Browse the repository at this point in the history
  • Loading branch information
rickhanlonii committed Jan 27, 2021
1 parent 5d50687 commit 79d0531
Show file tree
Hide file tree
Showing 17 changed files with 57 additions and 9 deletions.
2 changes: 1 addition & 1 deletion packages/react-dom/src/client/ReactDOMHostConfig.js
Expand Up @@ -392,7 +392,7 @@ export const queueMicrotask: any =
Promise.resolve(null)
.then(callback)
.catch(handleErrorInNextTick)
: scheduleTimeout;
: scheduleTimeout; // TODO: Determine the best fallback here.

function handleErrorInNextTick(error) {
setTimeout(() => {
Expand Down
Expand Up @@ -730,8 +730,15 @@ describe('ChangeEventPlugin', () => {

// Flush callbacks.
// Now the click update has flushed.
expect(Scheduler).toFlushAndYield(['render: ']);
expect(input.value).toBe('');
if (gate(flags => flags.enableDiscreteEventMicroTasks)) {
// Flush microtask queue.
await null;
expect(Scheduler).toHaveYielded(['render: ']);
expect(input.value).toBe('');
} else {
expect(Scheduler).toFlushAndYield(['render: ']);
expect(input.value).toBe('');
}
});

// @gate experimental
Expand Down
Expand Up @@ -470,11 +470,24 @@ describe('SimpleEventPlugin', function() {
'High-pri count: 7, Low-pri count: 0',
]);

// At the end, both counters should equal the total number of clicks
expect(Scheduler).toFlushAndYield([
'High-pri count: 8, Low-pri count: 0',
'High-pri count: 8, Low-pri count: 8',
]);
if (gate(flags => flags.enableDiscreteEventMicroTasks)) {
// Flush the microtask queue
await null;

// At the end, both counters should equal the total number of clicks
expect(Scheduler).toHaveYielded([
'High-pri count: 8, Low-pri count: 0',

// TODO: with cancellation, this required another flush?
'High-pri count: 8, Low-pri count: 8',
]);
} else {
// At the end, both counters should equal the total number of clicks
expect(Scheduler).toFlushAndYield([
'High-pri count: 8, Low-pri count: 0',
'High-pri count: 8, Low-pri count: 8',
]);
}
expect(button.textContent).toEqual('High-pri count: 8, Low-pri count: 8');
});
});
Expand Down
8 changes: 8 additions & 0 deletions packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Expand Up @@ -92,6 +92,7 @@ import {
warnsIfNotActing,
afterActiveInstanceBlur,
clearContainer,
queueMicrotask,
} from './ReactFiberHostConfig';

import {
Expand Down Expand Up @@ -216,6 +217,7 @@ import {
syncNestedUpdateFlag,
} from './ReactProfilerTimer.new';

import {enableDiscreteEventMicroTasks} from 'shared/ReactFeatureFlags';
// DEV stuff
import getComponentName from 'shared/getComponentName';
import ReactStrictModeWarnings from './ReactStrictModeWarnings.new';
Expand Down Expand Up @@ -745,6 +747,12 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
ImmediateSchedulerPriority,
performSyncWorkOnRoot.bind(null, root),
);
} else if (
enableDiscreteEventMicroTasks &&
newCallbackPriority === InputDiscreteLanePriority
) {
queueMicrotask(performSyncWorkOnRoot.bind(null, root));
newCallbackNode = null;
} else {
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
newCallbackPriority,
Expand Down
8 changes: 8 additions & 0 deletions packages/react-reconciler/src/ReactFiberWorkLoop.old.js
Expand Up @@ -34,6 +34,7 @@ import {
disableSchedulerTimeoutInWorkLoop,
enableDoubleInvokingEffects,
skipUnmountedBoundaries,
enableDiscreteEventMicroTasks,
} from 'shared/ReactFeatureFlags';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import invariant from 'shared/invariant';
Expand Down Expand Up @@ -92,6 +93,7 @@ import {
warnsIfNotActing,
afterActiveInstanceBlur,
clearContainer,
queueMicrotask,
} from './ReactFiberHostConfig';

import {
Expand Down Expand Up @@ -727,6 +729,12 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
ImmediateSchedulerPriority,
performSyncWorkOnRoot.bind(null, root),
);
} else if (
enableDiscreteEventMicroTasks &&
newCallbackPriority === InputDiscreteLanePriority
) {
queueMicrotask(performSyncWorkOnRoot.bind(null, root));
newCallbackNode = null;
} else {
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
newCallbackPriority,
Expand Down
Expand Up @@ -3528,6 +3528,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
});

// @gate enableCache
// @gate !enableDiscreteEventMicroTasks
it('regression: empty render at high priority causes update to be dropped', async () => {
// Reproduces a bug where flushDiscreteUpdates starts a new (empty) render
// pass which cancels a scheduled timeout and causes the fallback never to
Expand Down
2 changes: 1 addition & 1 deletion packages/react-test-renderer/src/ReactTestHostConfig.js
Expand Up @@ -228,7 +228,7 @@ export const queueMicrotask =
Promise.resolve(null)
.then(callback)
.catch(handleErrorInNextTick)
: scheduleTimeout;
: scheduleTimeout; // TODO: Determine the best fallback here.

function handleErrorInNextTick(error) {
setTimeout(() => {
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/ReactFeatureFlags.js
Expand Up @@ -152,3 +152,5 @@ export const disableSchedulerTimeoutInWorkLoop = false;

// Experiment to simplify/improve how transitions are scheduled
export const enableTransitionEntanglement = false;

export const enableDiscreteEventMicroTasks = false;
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-fb.js
Expand Up @@ -59,6 +59,7 @@ export const enableUseRefAccessWarning = false;
export const enableRecursiveCommitTraversal = false;
export const disableSchedulerTimeoutInWorkLoop = false;
export const enableTransitionEntanglement = false;
export const enableDiscreteEventMicroTasks = false;

// Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-oss.js
Expand Up @@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
export const enableRecursiveCommitTraversal = false;
export const disableSchedulerTimeoutInWorkLoop = false;
export const enableTransitionEntanglement = false;
export const enableDiscreteEventMicroTasks = false;

// Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.test-renderer.js
Expand Up @@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
export const enableRecursiveCommitTraversal = false;
export const disableSchedulerTimeoutInWorkLoop = false;
export const enableTransitionEntanglement = false;
export const enableDiscreteEventMicroTasks = false;

// Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars
Expand Down
Expand Up @@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
export const enableRecursiveCommitTraversal = false;
export const disableSchedulerTimeoutInWorkLoop = false;
export const enableTransitionEntanglement = false;
export const enableDiscreteEventMicroTasks = false;

// Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars
Expand Down
Expand Up @@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
export const enableRecursiveCommitTraversal = false;
export const disableSchedulerTimeoutInWorkLoop = false;
export const enableTransitionEntanglement = false;
export const enableDiscreteEventMicroTasks = false;

// Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.testing.js
Expand Up @@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
export const enableRecursiveCommitTraversal = false;
export const disableSchedulerTimeoutInWorkLoop = false;
export const enableTransitionEntanglement = false;
export const enableDiscreteEventMicroTasks = false;

// Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.testing.www.js
Expand Up @@ -58,6 +58,7 @@ export const enableUseRefAccessWarning = false;
export const enableRecursiveCommitTraversal = false;
export const disableSchedulerTimeoutInWorkLoop = false;
export const enableTransitionEntanglement = false;
export const enableDiscreteEventMicroTasks = false;

// Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.www-dynamic.js
Expand Up @@ -56,3 +56,4 @@ export const enableUseRefAccessWarning = __VARIANT__;
export const enableProfilerNestedUpdateScheduledHook = __VARIANT__;
export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
export const enableTransitionEntanglement = __VARIANT__;
export const enableDiscreteEventMicroTasks = __VARIANT__;
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.www.js
Expand Up @@ -32,6 +32,7 @@ export const {
disableNativeComponentFrames,
disableSchedulerTimeoutInWorkLoop,
enableTransitionEntanglement,
enableDiscreteEventMicroTasks,
} = dynamicFeatureFlags;

// On WWW, __EXPERIMENTAL__ is used for a new modern build.
Expand Down

0 comments on commit 79d0531

Please sign in to comment.