UNPKG

@refinedev/core

Version:

refine is a React-based framework for building internal tools, rapidly. It ships with Ant Design System, an enterprise-level UI toolkit.

64 lines (53 loc) 1.86 kB
import debounce from "lodash/debounce"; type Callbacks<T extends (...args: any) => any> = { resolve?: (value: Awaited<ReturnType<T>>) => void; reject?: (reason?: any) => void; }; type DebouncedFunction<T extends (...args: any) => any> = { (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>; flush: () => void; cancel: () => void; }; /** * Debounces sync and async functions with given wait time. The debounced function returns a promise which can be awaited or catched. * Only the last call of the debounced function will resolve or reject. * Previous calls will be rejected with the given cancelReason. * * The original debounce function doesn't work well with async functions, * It won't return a promise to resolve/reject and therefore it's not possible to await the result. * This will always return a promise to handle and await the result. * Previous calls will be rejected immediately after a new call made. */ export const asyncDebounce = <T extends (...args: any[]) => any>( func: T, wait = 1000, cancelReason?: string, ): DebouncedFunction<T> => { let callbacks: Array<Callbacks<T>> = []; const cancelPrevious = () => { callbacks.forEach((cb) => cb.reject?.(cancelReason)); callbacks = []; }; const debouncedFunc = debounce((...args: Parameters<T>) => { const { resolve, reject } = callbacks.pop() || {}; Promise.resolve(func(...args)) .then(resolve) .catch(reject); }, wait); const runner = (...args: Parameters<T>) => { return new Promise<Awaited<ReturnType<T>>>((resolve, reject) => { cancelPrevious(); callbacks.push({ resolve, reject, }); debouncedFunc(...args); }); }; runner.flush = () => debouncedFunc.flush(); runner.cancel = () => { debouncedFunc.cancel(); cancelPrevious(); }; return runner; };