rafz
Version:
requestAnimationFrame for libraries
152 lines (148 loc) • 3.47 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
let updateQueue = makeQueue();
const raf = (fn) => schedule(fn, updateQueue);
let writeQueue = makeQueue();
raf.write = (fn) => schedule(fn, writeQueue);
let onStartQueue = makeQueue();
raf.onStart = (fn) => schedule(fn, onStartQueue);
let onFrameQueue = makeQueue();
raf.onFrame = (fn) => schedule(fn, onFrameQueue);
let onFinishQueue = makeQueue();
raf.onFinish = (fn) => schedule(fn, onFinishQueue);
let timeouts = [];
raf.setTimeout = (handler, ms) => {
let time = raf.now() + ms;
let cancel = () => {
let i = timeouts.findIndex((t) => t.cancel == cancel);
if (~i)
timeouts.splice(i, 1);
__raf.count -= ~i ? 1 : 0;
};
let timeout = {time, handler, cancel};
timeouts.splice(findTimeout(time), 0, timeout);
__raf.count += 1;
start();
return timeout;
};
let findTimeout = (time) => ~(~timeouts.findIndex((t) => t.time > time) || ~timeouts.length);
raf.cancel = (fn) => {
updateQueue.delete(fn);
writeQueue.delete(fn);
};
raf.sync = (fn) => {
sync = true;
raf.batchedUpdates(fn);
sync = false;
};
raf.throttle = (fn) => {
let lastArgs;
function queuedFn() {
try {
fn(...lastArgs);
} finally {
lastArgs = null;
}
}
function throttled(...args) {
lastArgs = args;
raf.onStart(queuedFn);
}
throttled.handler = fn;
throttled.cancel = () => {
onStartQueue.delete(queuedFn);
lastArgs = null;
};
return throttled;
};
let nativeRaf = typeof window != "undefined" ? window.requestAnimationFrame : () => {
};
raf.use = (impl) => nativeRaf = impl;
raf.now = typeof performance != "undefined" ? () => performance.now() : Date.now;
raf.batchedUpdates = (fn) => fn();
raf.catch = console.error;
let ts = -1;
let sync = false;
function schedule(fn, queue) {
if (sync) {
queue.delete(fn);
fn(0);
} else {
queue.add(fn);
start();
}
}
function start() {
if (ts < 0) {
ts = 0;
nativeRaf(loop);
}
}
function loop() {
if (~ts) {
nativeRaf(loop);
raf.batchedUpdates(update);
}
}
function update() {
let prevTs = ts;
ts = raf.now();
let count = findTimeout(ts);
if (count) {
eachSafely(timeouts.splice(0, count), (t) => t.handler());
__raf.count -= count;
}
onStartQueue.flush();
updateQueue.flush(prevTs ? Math.min(64, ts - prevTs) : 16.667);
onFrameQueue.flush();
writeQueue.flush();
onFinishQueue.flush();
}
function makeQueue() {
let next = new Set();
let current = next;
return {
add(fn) {
__raf.count += current == next && !next.has(fn) ? 1 : 0;
next.add(fn);
},
delete(fn) {
__raf.count -= current == next && next.has(fn) ? 1 : 0;
return next.delete(fn);
},
flush(arg) {
if (current.size) {
next = new Set();
__raf.count -= current.size;
eachSafely(current, (fn) => fn(arg) && next.add(fn));
__raf.count += next.size;
current = next;
}
}
};
}
function eachSafely(values, each) {
values.forEach((value) => {
try {
each(value);
} catch (e) {
raf.catch(e);
}
});
}
const __raf = {
count: 0,
clear() {
ts = -1;
timeouts = [];
onStartQueue = makeQueue();
updateQueue = makeQueue();
onFrameQueue = makeQueue();
writeQueue = makeQueue();
onFinishQueue = makeQueue();
__raf.count = 0;
}
};
exports.__raf = __raf;
exports.raf = raf;
//# sourceMappingURL=raf.js.map