easeljs-react
Version:
React - EaselJS bindings with React Reconciler
130 lines (129 loc) • 5.26 kB
JavaScript
;
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"];
}