/** * @param {number} ms */ export function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } export function next() { return sleep(0); } /** * * @template {(...args: any[]) => any} F * @param {F} callback * @param {number} [wait] */ export function throttle(callback, wait = 1000) { /** @type {number | null} */ let timeoutId = null; /** @type {Parameters} */ let latestArgs; let hasTrailing = false; return (/** @type {Parameters} */ ...args) => { latestArgs = args; if (timeoutId) { hasTrailing = true; return; } callback(...latestArgs); timeoutId = setTimeout(() => { timeoutId = null; if (hasTrailing) { hasTrailing = false; callback(...latestArgs); } }, wait); }; } /** * @template {(...args: any[]) => any} F * @param {F} callback * @param {number} [wait] * @returns {((...args: Parameters) => void) & { cancel: () => void }} */ export function debounce(callback, wait = 1000) { /** @type {number | null} */ let timeoutId = null; const fn = (/** @type {Parameters} */ ...args) => { if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => { callback(...args); timeoutId = null; }, wait); }; fn.cancel = () => { if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } }; return fn; }