From 456dd3cf4afd3831fef5b162d7b4e57a80333b92 Mon Sep 17 00:00:00 2001 From: Emilis Baliukonis Date: Wed, 5 Aug 2020 13:12:46 +0300 Subject: [PATCH 1/3] Get current time from performance.now in non-DOM environments --- .../src/forks/SchedulerHostConfig.default.js | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/scheduler/src/forks/SchedulerHostConfig.default.js b/packages/scheduler/src/forks/SchedulerHostConfig.default.js index 9b802f01e2580..e68f3f9b13cec 100644 --- a/packages/scheduler/src/forks/SchedulerHostConfig.default.js +++ b/packages/scheduler/src/forks/SchedulerHostConfig.default.js @@ -16,6 +16,18 @@ export let requestPaint; export let getCurrentTime; export let forceFrameRate; +const performance = window.performance; +if ( + typeof performance === 'object' && + typeof performance.now === 'function' +) { + getCurrentTime = () => performance.now(); +} else { + const Date = window.Date; + const initialTime = Date.now(); + getCurrentTime = () => Date.now() - initialTime; +} + if ( // If Scheduler runs in a non-DOM environment, it falls back to a naive // implementation using setTimeout. @@ -40,10 +52,6 @@ if ( } } }; - const initialTime = Date.now(); - getCurrentTime = function() { - return Date.now() - initialTime; - }; requestHostCallback = function(cb) { if (_callback !== null) { // Protect against re-entrancy. @@ -68,8 +76,6 @@ if ( requestPaint = forceFrameRate = function() {}; } else { // Capture local references to native APIs, in case a polyfill overrides them. - const performance = window.performance; - const Date = window.Date; const setTimeout = window.setTimeout; const clearTimeout = window.clearTimeout; @@ -98,16 +104,6 @@ if ( } } - if ( - typeof performance === 'object' && - typeof performance.now === 'function' - ) { - getCurrentTime = () => performance.now(); - } else { - const initialTime = Date.now(); - getCurrentTime = () => Date.now() - initialTime; - } - let isMessageLoopRunning = false; let scheduledHostCallback = null; let taskTimeoutID = -1; From 1028878155806687c1456f735f1efda6ea1b6011 Mon Sep 17 00:00:00 2001 From: Emilis Baliukonis Date: Wed, 5 Aug 2020 13:31:49 +0300 Subject: [PATCH 2/3] Use local references to native APIs for Date and Performance --- .../scheduler/src/forks/SchedulerHostConfig.default.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/scheduler/src/forks/SchedulerHostConfig.default.js b/packages/scheduler/src/forks/SchedulerHostConfig.default.js index e68f3f9b13cec..8b24c2c082634 100644 --- a/packages/scheduler/src/forks/SchedulerHostConfig.default.js +++ b/packages/scheduler/src/forks/SchedulerHostConfig.default.js @@ -16,14 +16,16 @@ export let requestPaint; export let getCurrentTime; export let forceFrameRate; -const performance = window.performance; +const isWindowUndefined = typeof window === 'undefined'; + +const performance = isWindowUndefined ? global.performance : window.performance; if ( typeof performance === 'object' && typeof performance.now === 'function' ) { getCurrentTime = () => performance.now(); } else { - const Date = window.Date; + const Date = isWindowUndefined ? global.Date : window.Date; const initialTime = Date.now(); getCurrentTime = () => Date.now() - initialTime; } @@ -31,7 +33,7 @@ if ( if ( // If Scheduler runs in a non-DOM environment, it falls back to a naive // implementation using setTimeout. - typeof window === 'undefined' || + isWindowUndefined || // Check if MessageChannel is supported, too. typeof MessageChannel !== 'function' ) { From e35fbf02a5494f08544f4559cb1aeebfb7f41598 Mon Sep 17 00:00:00 2001 From: Emilis Baliukonis Date: Wed, 5 Aug 2020 17:15:16 +0300 Subject: [PATCH 3/3] Refactored to read globals directly --- .../src/__tests__/SchedulerBrowser-test.js | 12 ++++++----- .../src/forks/SchedulerHostConfig.default.js | 20 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/scheduler/src/__tests__/SchedulerBrowser-test.js b/packages/scheduler/src/__tests__/SchedulerBrowser-test.js index 90c527d87d7b8..50a9927ae3c6b 100644 --- a/packages/scheduler/src/__tests__/SchedulerBrowser-test.js +++ b/packages/scheduler/src/__tests__/SchedulerBrowser-test.js @@ -42,7 +42,7 @@ describe('SchedulerBrowser', () => { ); runtime = installMockBrowserRuntime(); - performance = window.performance; + performance = global.performance; Scheduler = require('scheduler'); cancelCallback = Scheduler.unstable_cancelCallback; scheduleCallback = Scheduler.unstable_scheduleCallback; @@ -50,6 +50,8 @@ describe('SchedulerBrowser', () => { }); afterEach(() => { + delete global.performance; + if (!runtime.isLogEmpty()) { throw Error('Test exited without clearing log.'); } @@ -63,17 +65,17 @@ describe('SchedulerBrowser', () => { let eventLog = []; - const window = {}; - global.window = window; - let currentTime = 0; - window.performance = { + global.performance = { now() { return currentTime; }, }; + const window = {}; + global.window = window; + // TODO: Scheduler no longer requires these methods to be polyfilled. But // maybe we want to continue warning if they don't exist, to preserve the // option to rely on it in the future? diff --git a/packages/scheduler/src/forks/SchedulerHostConfig.default.js b/packages/scheduler/src/forks/SchedulerHostConfig.default.js index 8b24c2c082634..998380bd110a3 100644 --- a/packages/scheduler/src/forks/SchedulerHostConfig.default.js +++ b/packages/scheduler/src/forks/SchedulerHostConfig.default.js @@ -16,24 +16,22 @@ export let requestPaint; export let getCurrentTime; export let forceFrameRate; -const isWindowUndefined = typeof window === 'undefined'; +const hasPerformanceNow = + typeof performance === 'object' && typeof performance.now === 'function'; -const performance = isWindowUndefined ? global.performance : window.performance; -if ( - typeof performance === 'object' && - typeof performance.now === 'function' -) { - getCurrentTime = () => performance.now(); +if (hasPerformanceNow) { + const localPerformance = performance; + getCurrentTime = () => localPerformance.now(); } else { - const Date = isWindowUndefined ? global.Date : window.Date; - const initialTime = Date.now(); - getCurrentTime = () => Date.now() - initialTime; + const localDate = Date; + const initialTime = localDate.now(); + getCurrentTime = () => localDate.now() - initialTime; } if ( // If Scheduler runs in a non-DOM environment, it falls back to a naive // implementation using setTimeout. - isWindowUndefined || + typeof window === 'undefined' || // Check if MessageChannel is supported, too. typeof MessageChannel !== 'function' ) {