diff --git a/packages/scheduler/src/SchedulerFeatureFlags.js b/packages/scheduler/src/SchedulerFeatureFlags.js index 08a0d979b621b..a5166f9813193 100644 --- a/packages/scheduler/src/SchedulerFeatureFlags.js +++ b/packages/scheduler/src/SchedulerFeatureFlags.js @@ -15,3 +15,5 @@ export const userBlockingPriorityTimeout = 250; export const normalPriorityTimeout = 5000; export const lowPriorityTimeout = 10000; export const enableRequestPaint = true; + +export const enableAlwaysYieldScheduler = __EXPERIMENTAL__; diff --git a/packages/scheduler/src/__tests__/Scheduler-test.js b/packages/scheduler/src/__tests__/Scheduler-test.js index fee1216d15730..64c31153de698 100644 --- a/packages/scheduler/src/__tests__/Scheduler-test.js +++ b/packages/scheduler/src/__tests__/Scheduler-test.js @@ -201,9 +201,10 @@ describe('SchedulerBrowser', () => { runtime.assertLog([ 'Message Event', 'Task', - SchedulerFeatureFlags.enableRequestPaint - ? 'Yield at 0ms' - : `Yield at ${SchedulerFeatureFlags.frameYieldMs}ms`, + gate(flags => flags.enableAlwaysYieldScheduler) && + !SchedulerFeatureFlags.enableRequestPaint + ? gate(flags => (flags.www ? 'Yield at 10ms' : 'Yield at 5ms')) + : 'Yield at 0ms', 'Post Message', ]); @@ -220,7 +221,13 @@ describe('SchedulerBrowser', () => { }); runtime.assertLog(['Post Message']); runtime.fireMessageEvent(); - runtime.assertLog(['Message Event', 'A', 'B']); + if (gate(flags => flags.enableAlwaysYieldScheduler)) { + runtime.assertLog(['Message Event', 'A', 'Post Message']); + runtime.fireMessageEvent(); + runtime.assertLog(['Message Event', 'B']); + } else { + runtime.assertLog(['Message Event', 'A', 'B']); + } }); it('multiple tasks with a yield in between', () => { @@ -267,6 +274,10 @@ describe('SchedulerBrowser', () => { runtime.assertLog(['Message Event', 'Oops!', 'Post Message']); runtime.fireMessageEvent(); + if (gate(flags => flags.enableAlwaysYieldScheduler)) { + runtime.assertLog(['Message Event', 'Post Message']); + runtime.fireMessageEvent(); + } runtime.assertLog(['Message Event', 'Yay']); }); diff --git a/packages/scheduler/src/__tests__/SchedulerSetImmediate-test.js b/packages/scheduler/src/__tests__/SchedulerSetImmediate-test.js index 7fd4a18db1930..74bbb8d55fbb7 100644 --- a/packages/scheduler/src/__tests__/SchedulerSetImmediate-test.js +++ b/packages/scheduler/src/__tests__/SchedulerSetImmediate-test.js @@ -188,7 +188,13 @@ describe('SchedulerDOMSetImmediate', () => { }); runtime.assertLog(['Set Immediate']); runtime.fireSetImmediate(); - runtime.assertLog(['setImmediate Callback', 'A', 'B']); + if (gate(flags => flags.enableAlwaysYieldScheduler)) { + runtime.assertLog(['setImmediate Callback', 'A', 'Set Immediate']); + runtime.fireSetImmediate(); + runtime.assertLog(['setImmediate Callback', 'B']); + } else { + runtime.assertLog(['setImmediate Callback', 'A', 'B']); + } }); it('multiple tasks at different priority', () => { @@ -200,7 +206,13 @@ describe('SchedulerDOMSetImmediate', () => { }); runtime.assertLog(['Set Immediate']); runtime.fireSetImmediate(); - runtime.assertLog(['setImmediate Callback', 'B', 'A']); + if (gate(flags => flags.enableAlwaysYieldScheduler)) { + runtime.assertLog(['setImmediate Callback', 'B', 'Set Immediate']); + runtime.fireSetImmediate(); + runtime.assertLog(['setImmediate Callback', 'A']); + } else { + runtime.assertLog(['setImmediate Callback', 'B', 'A']); + } }); it('multiple tasks with a yield in between', () => { @@ -246,7 +258,13 @@ describe('SchedulerDOMSetImmediate', () => { runtime.assertLog(['setImmediate Callback', 'Oops!', 'Set Immediate']); runtime.fireSetImmediate(); - runtime.assertLog(['setImmediate Callback', 'Yay']); + if (gate(flags => flags.enableAlwaysYieldScheduler)) { + runtime.assertLog(['setImmediate Callback', 'Set Immediate']); + runtime.fireSetImmediate(); + runtime.assertLog(['setImmediate Callback', 'Yay']); + } else { + runtime.assertLog(['setImmediate Callback', 'Yay']); + } }); it('schedule new task after queue has emptied', () => { diff --git a/packages/scheduler/src/forks/Scheduler.js b/packages/scheduler/src/forks/Scheduler.js index 68149a9fec14e..3fe4d1720fc38 100644 --- a/packages/scheduler/src/forks/Scheduler.js +++ b/packages/scheduler/src/forks/Scheduler.js @@ -19,6 +19,7 @@ import { lowPriorityTimeout, normalPriorityTimeout, enableRequestPaint, + enableAlwaysYieldScheduler, } from '../SchedulerFeatureFlags'; import {push, pop, peek} from '../SchedulerMinHeap'; @@ -196,9 +197,11 @@ function workLoop(initialTime: number) { currentTask !== null && !(enableSchedulerDebugging && isSchedulerPaused) ) { - if (currentTask.expirationTime > currentTime && shouldYieldToHost()) { - // This currentTask hasn't expired, and we've reached the deadline. - break; + if (!enableAlwaysYieldScheduler) { + if (currentTask.expirationTime > currentTime && shouldYieldToHost()) { + // This currentTask hasn't expired, and we've reached the deadline. + break; + } } // $FlowFixMe[incompatible-use] found when upgrading Flow const callback = currentTask.callback; @@ -242,6 +245,12 @@ function workLoop(initialTime: number) { pop(taskQueue); } currentTask = peek(taskQueue); + if (enableAlwaysYieldScheduler) { + if (currentTask === null || currentTask.expirationTime > currentTime) { + // This currentTask hasn't expired we yield to the browser task. + break; + } + } } // Return whether there's additional work if (currentTask !== null) { @@ -459,7 +468,7 @@ let frameInterval = frameYieldMs; let startTime = -1; function shouldYieldToHost(): boolean { - if (enableRequestPaint && needsPaint) { + if (!enableAlwaysYieldScheduler && enableRequestPaint && needsPaint) { // Yield now. return true; } diff --git a/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js b/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js index c65e2aea241f9..1d6b955eb8888 100644 --- a/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js +++ b/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js @@ -19,3 +19,5 @@ export const frameYieldMs = 10; export const userBlockingPriorityTimeout = 250; export const normalPriorityTimeout = 5000; export const lowPriorityTimeout = 10000; + +export const enableAlwaysYieldScheduler = false;