export async function sleep(ms: number, signal?: AbortSignal): Promise { return new Promise(resolve => { if (signal?.aborted) { resolve(); return; } let resolved = false; signal?.addEventListener('abort', () => { if (!resolved) { clearTimeout(timeId); resolve(); } }); const timeId = setTimeout(() => { resolved = true; resolve(); }, ms); }); } export function noop(_?: unknown) { return; } /** * @example * ```ts * const log = (message: string) => console.log(`[${new Date().toISOString()}] ${message}`); * * const throttledLog = throttle(log, 1000); * * throttledLog("Hello, world!"); * throttledLog("Hello, world!"); * throttledLog("Hello, world!"); * throttledLog("Hello, world!"); * throttledLog("Hello, world!"); * ``` */ export function throttle any>( fn: T, limit: number, options?: { leading?: boolean; trailing?: boolean } ): T; export function throttle< Args extends unknown[], T extends (...args: Args) => void, >( fn: (...args: Args) => void, limit: number, options?: { leading?: boolean; trailing?: boolean } ): T; export function throttle< Args extends unknown[], T extends (this: unknown, ...args: Args) => void, >(fn: T, limit: number, { leading = true, trailing = true } = {}): T { let timer: ReturnType | null = null; let lastArgs: Args | null = null; const setTimer = () => { if (lastArgs && trailing) { fn(...lastArgs); lastArgs = null; timer = setTimeout(setTimer, limit); } else { timer = null; } }; return function (this: unknown, ...args: Parameters) { if (timer) { // in throttle lastArgs = args; return; } // Execute the function on the leading edge if (leading) { fn.apply(this, args); } timer = setTimeout(setTimer, limit); } as T; } export const debounce = void>( fn: T, limit: number, { leading = true, trailing = true } = {} ): T => { let timer: ReturnType | null = null; let lastArgs: Parameters | null = null; // eslint-disable-next-line sonarjs/no-identical-functions const setTimer = () => { if (lastArgs && trailing) { fn(...lastArgs); lastArgs = null; timer = setTimeout(setTimer, limit); } else { timer = null; } }; return function (...args: Parameters) { if (timer) { lastArgs = args; clearTimeout(timer); } if (leading && !timer) { fn(...args); } timer = setTimeout(setTimer, limit); } as T; }; export async function nextTick() { // @ts-expect-error check window.scheduler if ('scheduler' in window && 'yield' in window.scheduler) { // @ts-expect-error check window.scheduler.yield return window.scheduler.yield(); } else if (typeof requestIdleCallback !== 'undefined') { return new Promise(resolve => requestIdleCallback(resolve)); } else { return new Promise(resolve => setTimeout(resolve, 0)); } }