From 36df483af4a626fd4021c060fcb0f62471e82af1 Mon Sep 17 00:00:00 2001 From: Ricky Date: Fri, 4 Sep 2020 10:58:17 -0400 Subject: [PATCH] Add feature flag to disable scheduler timeout in work loop (#19771) --- .../src/ReactFiberWorkLoop.new.js | 15 ++++++++++++++- .../src/ReactFiberWorkLoop.old.js | 15 ++++++++++++++- packages/shared/ReactFeatureFlags.js | 2 ++ .../shared/forks/ReactFeatureFlags.native-fb.js | 1 + .../shared/forks/ReactFeatureFlags.native-oss.js | 1 + .../forks/ReactFeatureFlags.test-renderer.js | 1 + .../ReactFeatureFlags.test-renderer.native.js | 1 + .../forks/ReactFeatureFlags.test-renderer.www.js | 1 + .../shared/forks/ReactFeatureFlags.testing.js | 1 + .../shared/forks/ReactFeatureFlags.testing.www.js | 1 + .../shared/forks/ReactFeatureFlags.www-dynamic.js | 1 + packages/shared/forks/ReactFeatureFlags.www.js | 1 + 12 files changed, 39 insertions(+), 2 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index 5e35b0404a..c2dc019d02 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -30,6 +30,7 @@ import { enableSchedulingProfiler, enableScopeAPI, skipUnmountedBoundaries, + disableSchedulerTimeoutInWorkLoop, } from 'shared/ReactFeatureFlags'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import invariant from 'shared/invariant'; @@ -750,7 +751,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // This is the entry point for every concurrent task, i.e. anything that // goes through Scheduler. -function performConcurrentWorkOnRoot(root) { +function performConcurrentWorkOnRoot(root, didTimeout) { // Since we know we're in a React event, we can clear the current // event time. The next update will compute a new event time. currentEventTime = NoTimestamp; @@ -790,6 +791,18 @@ function performConcurrentWorkOnRoot(root) { return null; } + // TODO: We only check `didTimeout` defensively, to account for a Scheduler + // bug we're still investigating. Once the bug in Scheduler is fixed, + // we can remove this, since we track expiration ourselves. + if (!disableSchedulerTimeoutInWorkLoop && didTimeout) { + // Something expired. Flush synchronously until there's no expired + // work left. + markRootExpired(root, lanes); + // This will schedule a synchronous callback. + ensureRootIsScheduled(root, now()); + return null; + } + let exitStatus = renderRootConcurrent(root, lanes); if ( diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js index a60e8a58f5..97514adb03 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js @@ -30,6 +30,7 @@ import { enableSchedulingProfiler, enableScopeAPI, skipUnmountedBoundaries, + disableSchedulerTimeoutInWorkLoop, } from 'shared/ReactFeatureFlags'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import invariant from 'shared/invariant'; @@ -738,7 +739,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) { // This is the entry point for every concurrent task, i.e. anything that // goes through Scheduler. -function performConcurrentWorkOnRoot(root) { +function performConcurrentWorkOnRoot(root, didTimeout) { // Since we know we're in a React event, we can clear the current // event time. The next update will compute a new event time. currentEventTime = NoTimestamp; @@ -778,6 +779,18 @@ function performConcurrentWorkOnRoot(root) { return null; } + // TODO: We only check `didTimeout` defensively, to account for a Scheduler + // bug we're still investigating. Once the bug in Scheduler is fixed, + // we can remove this, since we track expiration ourselves. + if (!disableSchedulerTimeoutInWorkLoop && didTimeout) { + // Something expired. Flush synchronously until there's no expired + // work left. + markRootExpired(root, lanes); + // This will schedule a synchronous callback. + ensureRootIsScheduled(root, now()); + return null; + } + let exitStatus = renderRootConcurrent(root, lanes); if ( diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index f97c348759..8ee92ed33c 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -137,3 +137,5 @@ export const enableDiscreteEventFlushingChange = false; export const enablePassiveEventIntervention = true; export const enableEagerRootListeners = true; + +export const disableSchedulerTimeoutInWorkLoop = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index a919202477..aa78ef983a 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -51,6 +51,7 @@ export const decoupleUpdatePriorityFromScheduler = false; export const enableDiscreteEventFlushingChange = false; export const enablePassiveEventIntervention = true; export const enableEagerRootListeners = true; +export const disableSchedulerTimeoutInWorkLoop = false; // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index dd6aaafa88..61b197a495 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -50,6 +50,7 @@ export const decoupleUpdatePriorityFromScheduler = false; export const enableDiscreteEventFlushingChange = false; export const enablePassiveEventIntervention = true; export const enableEagerRootListeners = true; +export const disableSchedulerTimeoutInWorkLoop = false; // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index e716d49829..c4090f03ce 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -50,6 +50,7 @@ export const decoupleUpdatePriorityFromScheduler = false; export const enableDiscreteEventFlushingChange = false; export const enablePassiveEventIntervention = true; export const enableEagerRootListeners = true; +export const disableSchedulerTimeoutInWorkLoop = false; // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js index a353dafcf7..57ae05f300 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js @@ -50,6 +50,7 @@ export const decoupleUpdatePriorityFromScheduler = false; export const enableDiscreteEventFlushingChange = false; export const enablePassiveEventIntervention = true; export const enableEagerRootListeners = true; +export const disableSchedulerTimeoutInWorkLoop = false; // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 8a708c5bcf..184a7e99c6 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -50,6 +50,7 @@ export const decoupleUpdatePriorityFromScheduler = false; export const enableDiscreteEventFlushingChange = false; export const enablePassiveEventIntervention = true; export const enableEagerRootListeners = true; +export const disableSchedulerTimeoutInWorkLoop = false; // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars diff --git a/packages/shared/forks/ReactFeatureFlags.testing.js b/packages/shared/forks/ReactFeatureFlags.testing.js index 99b3ec5346..5882182654 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.js @@ -50,6 +50,7 @@ export const decoupleUpdatePriorityFromScheduler = false; export const enableDiscreteEventFlushingChange = false; export const enablePassiveEventIntervention = true; export const enableEagerRootListeners = true; +export const disableSchedulerTimeoutInWorkLoop = false; // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars diff --git a/packages/shared/forks/ReactFeatureFlags.testing.www.js b/packages/shared/forks/ReactFeatureFlags.testing.www.js index c441fbd723..14d1c8839a 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.www.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.www.js @@ -50,6 +50,7 @@ export const decoupleUpdatePriorityFromScheduler = false; export const enableDiscreteEventFlushingChange = true; export const enablePassiveEventIntervention = true; export const enableEagerRootListeners = true; +export const disableSchedulerTimeoutInWorkLoop = false; // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index 2ffdff0853..301da30b57 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -48,3 +48,4 @@ export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; // to __VARIANT__. export const enableTrustedTypesIntegration = false; export const disableSchedulerTimeoutBasedOnReactExpirationTime = false; +export const disableSchedulerTimeoutInWorkLoop = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index fe7a0a7a66..0647411176 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -29,6 +29,7 @@ export const { skipUnmountedBoundaries, enablePassiveEventIntervention, enableEagerRootListeners, + disableSchedulerTimeoutInWorkLoop, } = dynamicFeatureFlags; // On WWW, __EXPERIMENTAL__ is used for a new modern build.