preemptive-animation-frame
Version:
Preemptive requestAnimationFrame
115 lines (97 loc) • 10.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.forceAnimationFrame = exports.cancelAnimationFrame = exports.requestAnimationFrame = exports.now = undefined;
var _requestPolyfilledAnimationFrame = require('request-polyfilled-animation-frame');
var RAF = _interopRequireWildcard(_requestPolyfilledAnimationFrame);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
// Invariants:
// 1. In the NO_REQUEST state, there is never a scheduled animation frame.
// 2. In the PENDING_REQUEST and EXTRA_REQUEST states, there is always exactly
// one scheduled animation frame.
var NO_REQUEST = 0;
var PENDING_REQUEST = 1;
var EXTRA_REQUEST = 2;
var requestID = null;
var nextID = 0;
var state = NO_REQUEST;
var requests = [];
var ids = [];
var absent = new Error('absent');
var now = exports.now = RAF.now;
var requestAnimationFrame = exports.requestAnimationFrame = function requestAnimationFrame(request) {
if (state === NO_REQUEST) {
requestID = RAF.requestAnimationFrame(performAnimationFrame);
}
var id = ++nextID;
requests.push(request);
ids.push(id);
state = PENDING_REQUEST;
return id;
};
var cancelAnimationFrame = exports.cancelAnimationFrame = function cancelAnimationFrame(id) {
var index = ids.indexOf(id);
if (index >= 0) {
ids.splice(index, 1);
requests.splice(index, 1);
}
};
var forceAnimationFrame = exports.forceAnimationFrame = function forceAnimationFrame() {
var time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : now();
switch (state) {
case NO_REQUEST:
break;
default:
if (requestID != null) {
RAF.cancelAnimationFrame(requestID);
requestID = null;
}
performAnimationFrame(time);
}
};
var performAnimationFrame = function performAnimationFrame(time) {
switch (state) {
case NO_REQUEST:
// This state should not be possible. How can there be no
// request, yet somehow we are actively fulfilling a
// request?
throw Error('Unexpected frame request');
case PENDING_REQUEST:
// At this point, we do not *know* that another frame is
// needed, but we make an extra frame request just in
// case. It's possible to drop a frame if frame is requested
// too late, so we just do it preemptively.
requestID = RAF.requestAnimationFrame(performAnimationFrame);
state = EXTRA_REQUEST;
ids.splice(0);
dispatchAnimationFrame(requests.splice(0), 0, time);
break;
case EXTRA_REQUEST:
// Turns out the extra request was not needed, so we will
// stop requesting. No reason to call it all the time if
// no one needs it.
state = NO_REQUEST;
break;
}
};
var dispatchAnimationFrame = function dispatchAnimationFrame(requests, index, time) {
var exception = absent;
var count = requests.length;
try {
while (index < count) {
var request = requests[index];
index = index + 1;
request(time);
}
} catch (error) {
exception = error;
}
if (index < count) {
dispatchAnimationFrame(requests, index, time);
}
if (exception !== absent) {
throw exception;
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9wcmVlbXB0aXZlLWFuaW1hdGlvbi1mcmFtZS5qcyJdLCJuYW1lcyI6WyJSQUYiLCJOT19SRVFVRVNUIiwiUEVORElOR19SRVFVRVNUIiwiRVhUUkFfUkVRVUVTVCIsInJlcXVlc3RJRCIsIm5leHRJRCIsInN0YXRlIiwicmVxdWVzdHMiLCJpZHMiLCJhYnNlbnQiLCJFcnJvciIsIm5vdyIsInJlcXVlc3RBbmltYXRpb25GcmFtZSIsInJlcXVlc3QiLCJwZXJmb3JtQW5pbWF0aW9uRnJhbWUiLCJpZCIsInB1c2giLCJjYW5jZWxBbmltYXRpb25GcmFtZSIsImluZGV4IiwiaW5kZXhPZiIsInNwbGljZSIsImZvcmNlQW5pbWF0aW9uRnJhbWUiLCJ0aW1lIiwiZGlzcGF0Y2hBbmltYXRpb25GcmFtZSIsImV4Y2VwdGlvbiIsImNvdW50IiwibGVuZ3RoIiwiZXJyb3IiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFFQTs7SUFBWUEsRzs7OztBQUtaO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBTUMsYUFBYSxDQUFuQjs7QUFDQSxJQUFNQyxrQkFBa0IsQ0FBeEI7QUFDQSxJQUFNQyxnQkFBZ0IsQ0FBdEI7O0FBRUEsSUFBSUMsWUFBb0IsSUFBeEI7QUFDQSxJQUFJQyxTQUFnQixDQUFwQjtBQUNBLElBQUlDLFFBQWNMLFVBQWxCO0FBQ0EsSUFBSU0sV0FBcUMsRUFBekM7QUFDQSxJQUFJQyxNQUFvQixFQUF4Qjs7QUFFQSxJQUFNQyxTQUFTLElBQUlDLEtBQUosQ0FBVSxRQUFWLENBQWY7O0FBRU8sSUFBTUMsb0JBQU1YLElBQUlXLEdBQWhCOztBQUVBLElBQU1DLHdEQUF3QixTQUF4QkEscUJBQXdCLENBQUtDLE9BQUwsRUFBa0M7QUFDckUsTUFBSVAsVUFBVUwsVUFBZCxFQUEwQjtBQUN4QkcsZ0JBQVlKLElBQUlZLHFCQUFKLENBQTBCRSxxQkFBMUIsQ0FBWjtBQUNEOztBQUVELE1BQU1DLEtBQUssRUFBRVYsTUFBYjtBQUNBRSxXQUFTUyxJQUFULENBQWNILE9BQWQ7QUFDQUwsTUFBSVEsSUFBSixDQUFTRCxFQUFUO0FBQ0FULFVBQVFKLGVBQVI7QUFDQSxTQUFPYSxFQUFQO0FBQ0QsQ0FWTTs7QUFZQSxJQUFNRSxzREFDWCxTQURXQSxvQkFDWCxDQUFDRixFQUFELEVBQW9CO0FBQ2xCLE1BQU1HLFFBQVFWLElBQUlXLE9BQUosQ0FBWUosRUFBWixDQUFkO0FBQ0EsTUFBSUcsU0FBUyxDQUFiLEVBQWdCO0FBQ2RWLFFBQUlZLE1BQUosQ0FBV0YsS0FBWCxFQUFrQixDQUFsQjtBQUNBWCxhQUFTYSxNQUFULENBQWdCRixLQUFoQixFQUF1QixDQUF2QjtBQUNEO0FBQ0YsQ0FQSTs7QUFTQSxJQUFNRyxvREFDWCxTQURXQSxtQkFDWCxHQUFxQjtBQUFBLE1BQXBCQyxJQUFvQix1RUFBVlgsS0FBVTs7QUFDbkIsVUFBUUwsS0FBUjtBQUNFLFNBQUtMLFVBQUw7QUFDRTtBQUNGO0FBQ0UsVUFBSUcsYUFBYSxJQUFqQixFQUF1QjtBQUNyQkosWUFBSWlCLG9CQUFKLENBQXlCYixTQUF6QjtBQUNBQSxvQkFBWSxJQUFaO0FBQ0Q7QUFDRFUsNEJBQXNCUSxJQUF0QjtBQVJKO0FBVUQsQ0FaSTs7QUFjUCxJQUFNUix3QkFDSixTQURJQSxxQkFDSixDQUFDUSxJQUFELEVBQWU7QUFDYixVQUFRaEIsS0FBUjtBQUNFLFNBQUtMLFVBQUw7QUFDRTtBQUNBO0FBQ0E7QUFDQSxZQUFNUyxNQUFNLDBCQUFOLENBQU47QUFDRixTQUFLUixlQUFMO0FBQ0U7QUFDQTtBQUNBO0FBQ0E7QUFDQUUsa0JBQVlKLElBQUlZLHFCQUFKLENBQTBCRSxxQkFBMUIsQ0FBWjtBQUNBUixjQUFRSCxhQUFSO0FBQ0FLLFVBQUlZLE1BQUosQ0FBVyxDQUFYO0FBQ0FHLDZCQUF1QmhCLFNBQVNhLE1BQVQsQ0FBZ0IsQ0FBaEIsQ0FBdkIsRUFBMkMsQ0FBM0MsRUFBOENFLElBQTlDO0FBQ0E7QUFDRixTQUFLbkIsYUFBTDtBQUNFO0FBQ0E7QUFDQTtBQUNBRyxjQUFRTCxVQUFSO0FBQ0E7QUFyQko7QUF1QkQsQ0F6Qkg7O0FBMkJBLElBQU1zQix5QkFBeUIsU0FBekJBLHNCQUF5QixDQUFLaEIsUUFBTCxFQUNLVyxLQURMLEVBRUtJLElBRkwsRUFFbUI7QUFDaEQsTUFBSUUsWUFBWWYsTUFBaEI7QUFDQSxNQUFNZ0IsUUFBUWxCLFNBQVNtQixNQUF2QjtBQUNBLE1BQUk7QUFDRixXQUFPUixRQUFRTyxLQUFmLEVBQXNCO0FBQ3BCLFVBQU1aLFVBQVVOLFNBQVNXLEtBQVQsQ0FBaEI7QUFDQUEsY0FBUUEsUUFBUSxDQUFoQjtBQUNBTCxjQUFRUyxJQUFSO0FBQ0Q7QUFDRixHQU5ELENBTUUsT0FBT0ssS0FBUCxFQUFjO0FBQ2RILGdCQUFZRyxLQUFaO0FBQ0Q7O0FBRUQsTUFBSVQsUUFBUU8sS0FBWixFQUFtQjtBQUNqQkYsMkJBQXVCaEIsUUFBdkIsRUFBaUNXLEtBQWpDLEVBQXdDSSxJQUF4QztBQUNEOztBQUVELE1BQUlFLGNBQWNmLE1BQWxCLEVBQTBCO0FBQ3hCLFVBQU1lLFNBQU47QUFDRDtBQUNGLENBdEJEIiwiZmlsZSI6InByZWVtcHRpdmUtYW5pbWF0aW9uLWZyYW1lLmpzIiwic291cmNlUm9vdCI6InNyYyIsInNvdXJjZXNDb250ZW50IjpbIi8qIEBmbG93ICovXG5cbmltcG9ydCAqIGFzIFJBRiBmcm9tICdyZXF1ZXN0LXBvbHlmaWxsZWQtYW5pbWF0aW9uLWZyYW1lJ1xuXG50eXBlIFRpbWUgPSBudW1iZXJcbnR5cGUgU3RhdGUgPSAwIHwgMSB8IDJcblxuLy8gSW52YXJpYW50czpcbi8vIDEuIEluIHRoZSBOT19SRVFVRVNUIHN0YXRlLCB0aGVyZSBpcyBuZXZlciBhIHNjaGVkdWxlZCBhbmltYXRpb24gZnJhbWUuXG4vLyAyLiBJbiB0aGUgUEVORElOR19SRVFVRVNUIGFuZCBFWFRSQV9SRVFVRVNUIHN0YXRlcywgdGhlcmUgaXMgYWx3YXlzIGV4YWN0bHlcbi8vIG9uZSBzY2hlZHVsZWQgYW5pbWF0aW9uIGZyYW1lLlxuY29uc3QgTk9fUkVRVUVTVCA9IDBcbmNvbnN0IFBFTkRJTkdfUkVRVUVTVCA9IDFcbmNvbnN0IEVYVFJBX1JFUVVFU1QgPSAyXG5cbmxldCByZXF1ZXN0SUQ6P251bWJlciA9IG51bGxcbmxldCBuZXh0SUQ6bnVtYmVyID0gMFxubGV0IHN0YXRlOlN0YXRlID0gTk9fUkVRVUVTVFxubGV0IHJlcXVlc3RzOkFycmF5PCh0aW1lOlRpbWUpID0+IGFueT4gPSBbXVxubGV0IGlkczpBcnJheTxudW1iZXI+ID0gW11cblxuY29uc3QgYWJzZW50ID0gbmV3IEVycm9yKCdhYnNlbnQnKVxuXG5leHBvcnQgY29uc3Qgbm93ID0gUkFGLm5vd1xuXG5leHBvcnQgY29uc3QgcmVxdWVzdEFuaW1hdGlvbkZyYW1lID0gPGE+IChyZXF1ZXN0Oih0aW1lOlRpbWUpID0+IGEpID0+IHtcbiAgaWYgKHN0YXRlID09PSBOT19SRVFVRVNUKSB7XG4gICAgcmVxdWVzdElEID0gUkFGLnJlcXVlc3RBbmltYXRpb25GcmFtZShwZXJmb3JtQW5pbWF0aW9uRnJhbWUpXG4gIH1cblxuICBjb25zdCBpZCA9ICsrbmV4dElEXG4gIHJlcXVlc3RzLnB1c2gocmVxdWVzdClcbiAgaWRzLnB1c2goaWQpXG4gIHN0YXRlID0gUEVORElOR19SRVFVRVNUXG4gIHJldHVybiBpZFxufVxuXG5leHBvcnQgY29uc3QgY2FuY2VsQW5pbWF0aW9uRnJhbWUgPVxuICAoaWQ6bnVtYmVyKTp2b2lkID0+IHtcbiAgICBjb25zdCBpbmRleCA9IGlkcy5pbmRleE9mKGlkKVxuICAgIGlmIChpbmRleCA+PSAwKSB7XG4gICAgICBpZHMuc3BsaWNlKGluZGV4LCAxKVxuICAgICAgcmVxdWVzdHMuc3BsaWNlKGluZGV4LCAxKVxuICAgIH1cbiAgfVxuXG5leHBvcnQgY29uc3QgZm9yY2VBbmltYXRpb25GcmFtZSA9XG4gICh0aW1lOlRpbWU9bm93KCkpID0+IHtcbiAgICBzd2l0Y2ggKHN0YXRlKSB7XG4gICAgICBjYXNlIE5PX1JFUVVFU1Q6XG4gICAgICAgIGJyZWFrXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAocmVxdWVzdElEICE9IG51bGwpIHtcbiAgICAgICAgICBSQUYuY2FuY2VsQW5pbWF0aW9uRnJhbWUocmVxdWVzdElEKVxuICAgICAgICAgIHJlcXVlc3RJRCA9IG51bGxcbiAgICAgICAgfVxuICAgICAgICBwZXJmb3JtQW5pbWF0aW9uRnJhbWUodGltZSlcbiAgICB9XG4gIH1cblxuY29uc3QgcGVyZm9ybUFuaW1hdGlvbkZyYW1lID1cbiAgKHRpbWU6VGltZSkgPT4ge1xuICAgIHN3aXRjaCAoc3RhdGUpIHtcbiAgICAgIGNhc2UgTk9fUkVRVUVTVDpcbiAgICAgICAgLy8gVGhpcyBzdGF0ZSBzaG91bGQgbm90IGJlIHBvc3NpYmxlLiBIb3cgY2FuIHRoZXJlIGJlIG5vXG4gICAgICAgIC8vIHJlcXVlc3QsIHlldCBzb21laG93IHdlIGFyZSBhY3RpdmVseSBmdWxmaWxsaW5nIGFcbiAgICAgICAgLy8gcmVxdWVzdD9cbiAgICAgICAgdGhyb3cgRXJyb3IoJ1VuZXhwZWN0ZWQgZnJhbWUgcmVxdWVzdCcpXG4gICAgICBjYXNlIFBFTkRJTkdfUkVRVUVTVDpcbiAgICAgICAgLy8gQXQgdGhpcyBwb2ludCwgd2UgZG8gbm90ICprbm93KiB0aGF0IGFub3RoZXIgZnJhbWUgaXNcbiAgICAgICAgLy8gbmVlZGVkLCBidXQgd2UgbWFrZSBhbiBleHRyYSBmcmFtZSByZXF1ZXN0IGp1c3QgaW5cbiAgICAgICAgLy8gY2FzZS4gSXQncyBwb3NzaWJsZSB0byBkcm9wIGEgZnJhbWUgaWYgZnJhbWUgaXMgcmVxdWVzdGVkXG4gICAgICAgIC8vIHRvbyBsYXRlLCBzbyB3ZSBqdXN0IGRvIGl0IHByZWVtcHRpdmVseS5cbiAgICAgICAgcmVxdWVzdElEID0gUkFGLnJlcXVlc3RBbmltYXRpb25GcmFtZShwZXJmb3JtQW5pbWF0aW9uRnJhbWUpXG4gICAgICAgIHN0YXRlID0gRVhUUkFfUkVRVUVTVFxuICAgICAgICBpZHMuc3BsaWNlKDApXG4gICAgICAgIGRpc3BhdGNoQW5pbWF0aW9uRnJhbWUocmVxdWVzdHMuc3BsaWNlKDApLCAwLCB0aW1lKVxuICAgICAgICBicmVha1xuICAgICAgY2FzZSBFWFRSQV9SRVFVRVNUOlxuICAgICAgICAvLyBUdXJucyBvdXQgdGhlIGV4dHJhIHJlcXVlc3Qgd2FzIG5vdCBuZWVkZWQsIHNvIHdlIHdpbGxcbiAgICAgICAgLy8gc3RvcCByZXF1ZXN0aW5nLiBObyByZWFzb24gdG8gY2FsbCBpdCBhbGwgdGhlIHRpbWUgaWZcbiAgICAgICAgLy8gbm8gb25lIG5lZWRzIGl0LlxuICAgICAgICBzdGF0ZSA9IE5PX1JFUVVFU1RcbiAgICAgICAgYnJlYWtcbiAgICB9XG4gIH1cblxuY29uc3QgZGlzcGF0Y2hBbmltYXRpb25GcmFtZSA9IDxhPiAocmVxdWVzdHM6QXJyYXk8KHRpbWU6VGltZSkgPT4gYT4sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRleDpudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lOlRpbWUpID0+IHtcbiAgbGV0IGV4Y2VwdGlvbiA9IGFic2VudFxuICBjb25zdCBjb3VudCA9IHJlcXVlc3RzLmxlbmd0aFxuICB0cnkge1xuICAgIHdoaWxlIChpbmRleCA8IGNvdW50KSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gcmVxdWVzdHNbaW5kZXhdXG4gICAgICBpbmRleCA9IGluZGV4ICsgMVxuICAgICAgcmVxdWVzdCh0aW1lKVxuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBleGNlcHRpb24gPSBlcnJvclxuICB9XG5cbiAgaWYgKGluZGV4IDwgY291bnQpIHtcbiAgICBkaXNwYXRjaEFuaW1hdGlvbkZyYW1lKHJlcXVlc3RzLCBpbmRleCwgdGltZSlcbiAgfVxuXG4gIGlmIChleGNlcHRpb24gIT09IGFic2VudCkge1xuICAgIHRocm93IGV4Y2VwdGlvblxuICB9XG59XG4iXX0=