Skip to content

Instantly share code, notes, and snippets.

@romelperez
Last active February 26, 2022 04:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save romelperez/d36991f8225b124c3b1a9ebabbcbec67 to your computer and use it in GitHub Desktop.
Save romelperez/d36991f8225b124c3b1a9ebabbcbec67 to your computer and use it in GitHub Desktop.
Request Animation Frame Task Scheduler
import { isBrowser } from './browser';
type RAFSchedulerId = number | string;
type RAFSchedulerCallback = () => unknown;
// TODO: How to handle suspended schedules on suspended window?
const raf = (delay: number, callback: RAFSchedulerCallback): () => void => {
let scheduleId: number | undefined;
const start = Date.now();
const checker = (): void => {
const slapsed = Date.now() - start;
if (slapsed >= delay) {
callback();
}
else {
scheduleId = window.requestAnimationFrame(checker);
}
};
scheduleId = window.requestAnimationFrame(checker);
return () => {
if (scheduleId !== undefined) {
window.cancelAnimationFrame(scheduleId);
}
};
};
declare function RAFSchedulerStart (id: RAFSchedulerId, time: number, callback: RAFSchedulerCallback): void;
declare function RAFSchedulerStart (time: number, callback: RAFSchedulerCallback): void;
interface RAFScheduler {
stop: (id: RAFSchedulerId) => void
stopAll: () => void
start: typeof RAFSchedulerStart
isPending: (id?: RAFSchedulerId) => boolean
}
function createRAFScheduler (): RAFScheduler {
const timeouts: Record<RAFSchedulerId, RAFSchedulerCallback> = {};
const clean = (id: RAFSchedulerId): void => {
delete timeouts[id]; // eslint-disable-line @typescript-eslint/no-dynamic-delete
};
const stop = (id: RAFSchedulerId): void => {
timeouts[id]?.();
clean(id);
};
const stopAll = (): void => {
Object.keys(timeouts).forEach(stop);
};
const start = (a: RAFSchedulerId | number, b: RAFSchedulerCallback | number, c?: RAFSchedulerCallback): void => {
if (!isBrowser) {
return;
}
const id = c ? a : '';
const time = (c ? b : a) as number;
const callback: () => unknown = c || b as RAFSchedulerCallback;
stop(id);
timeouts[id] = raf(time, () => {
clean(id);
callback();
});
};
const isPending = (id?: RAFSchedulerId): boolean => {
return timeouts[id ?? ''] !== undefined;
};
return Object.freeze({ stop, stopAll, start, isPending });
}
export type { RAFScheduler };
export { createRAFScheduler };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment