UNPKG

easeljs-react

Version:

React - EaselJS bindings with React Reconciler

130 lines (129 loc) 5.26 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); // This is a built-in polyfill for requestIdleCallback. It works by scheduling // a requestAnimationFrame, storing the time for the start of the frame, then // scheduling a postMessage which gets scheduled after paint. Within the // postMessage handler do as much work as possible until time + frame rate. // By separating the idle call into a separate event tick we ensure that // layout, paint and other browser work is counted against the available time. // The frame rate is dynamically adjusted. const now_1 = require("./now"); const kCanUseDOM = typeof window !== 'undefined' && window.document && window.document.createElement; // TODO: There's no way to cancel, because Fiber doesn't atm. let _rIC; exports.requestIdleCallback = _rIC; if (!kCanUseDOM) { exports.requestIdleCallback = _rIC = function (frameCallback) { setTimeout(() => { frameCallback({ timeRemaining() { return Infinity; } }); }); return 0; }; } else if (typeof global["requestIdleCallback"] !== 'function') { // Polyfill requestIdleCallback. var scheduledRAFCallback = null; var scheduledRICCallback = null; var isIdleScheduled = false; var isAnimationFrameScheduled = false; var frameDeadline = 0; // We start out assuming that we run at 30fps but then the heuristic tracking // will adjust this value to a faster fps if we get more frequent animation // frames. var previousFrameTime = 33; var activeFrameTime = 33; var frameDeadlineObject; if (now_1.kHasNativePerformanceNow) { frameDeadlineObject = { timeRemaining() { // We assume that if we have a performance timer that the rAF callback // gets a performance timer value. Not sure if this is always true. return frameDeadline - performance.now(); } }; } else { frameDeadlineObject = { timeRemaining() { // Fallback to Date.now() return frameDeadline - Date.now(); } }; } // We use the postMessage trick to defer idle work until after the repaint. var messageKey = '__reactIdleCallback$' + Math.random() .toString(36) .slice(2); var idleTick = function (event) { if (event.source !== window || event.data !== messageKey) { return; } isIdleScheduled = false; var callback = scheduledRICCallback; scheduledRICCallback = null; if (callback !== null) { callback(frameDeadlineObject); } }; // Assumes that we have addEventListener in this environment. Might need // something better for old IE. window.addEventListener('message', idleTick, false); var animationTick = function (rafTime) { isAnimationFrameScheduled = false; var nextFrameTime = rafTime - frameDeadline + activeFrameTime; if (nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime) { if (nextFrameTime < 8) { // Defensive coding. We don't support higher frame rates than 120hz. // If we get lower than that, it is probably a bug. nextFrameTime = 8; } // If one frame goes long, then the next one can be short to catch up. // If two frames are short in a row, then that's an indication that we // actually have a higher frame rate than what we're currently optimizing. // We adjust our heuristic dynamically accordingly. For example, if we're // running on 120hz display or 90hz VR display. // Take the max of the two in case one of them was an anomaly due to // missed frame deadlines. activeFrameTime = nextFrameTime < previousFrameTime ? previousFrameTime : nextFrameTime; } else { previousFrameTime = nextFrameTime; } frameDeadline = rafTime + activeFrameTime; if (!isIdleScheduled) { isIdleScheduled = true; window.postMessage(messageKey, '*'); } var callback = scheduledRAFCallback; scheduledRAFCallback = null; if (callback !== null) { callback(rafTime); } }; exports.requestIdleCallback = _rIC = function (callback) { // This assumes that we only schedule one callback at a time because that's // how Fiber uses it. scheduledRICCallback = callback; if (!isAnimationFrameScheduled) { // If rAF didn't already schedule one, we need to schedule a frame. // TODO: If this rAF doesn't materialize because the browser throttles, we // might want to still have setTimeout trigger rIC as a backup to ensure // that we keep performing work. isAnimationFrameScheduled = true; requestAnimationFrame(animationTick); } return 0; }; } else { exports.requestIdleCallback = _rIC = global["requestIdleCallback"]; }