rc-js-util
Version:
A collection of TS and C++ utilities to help writing performant and correct applications, achieved through strict typing and (removable) invariant checking.
94 lines (82 loc) • 2.32 kB
text/typescript
/**
* @public
*/
export type TDebouncedFn<TArgs extends unknown[]> =
& ((...args: TArgs) => void)
& { cancel: () => void }
;
/**
* @public
* Creates a function that will proxy calls to `functionToProxy` when `wait` time has passed since the last call, using the
* most recent arguments. Where `immediate` is true, the function immediately proxies the call and will not proxy again until
* `wait` time passes since the last call.
*
* @param functionToProxy - The function to debounce.
* @param wait - Time to wait in ms.
* @param immediate - If true run on the leading edge, default false.
* @returns A debounced function.
*
* @remarks
* As per underscore's debounce, except that returns have been disallowed.
* See {@link fpDebounce}.
*/
export function fpDebounce<TArgs extends unknown[]>
(
wait: number,
immediate: boolean,
functionToProxy: (...args: TArgs) => void,
)
: TDebouncedFn<TArgs>
{
let timeout: number | undefined;
let previous: number;
let args: TArgs | null;
let context: unknown;
function later()
{
const passed = Date.now() - previous;
if (wait > passed)
{
timeout = setTimeout(later, wait - passed);
}
else
{
timeout = undefined;
if (!immediate)
{
functionToProxy.apply(context, args as TArgs);
}
// This check is needed because `func` can recursively invoke `debounced`.
if (timeout == null)
{
args = context = null;
}
}
}
const debounced: TDebouncedFn<TArgs> = function (this: unknown, ..._args: TArgs): number
{
args = _args;
previous = Date.now();
if (timeout == null)
{
timeout = setTimeout(later, wait);
if (immediate)
{
functionToProxy.apply(this, args);
}
}
return timeout;
};
debounced.cancel = function ()
{
clearTimeout(timeout);
};
return debounced;
}
declare const setTimeout: <TArgs extends unknown[]>
(
functionToProxy: (...args: TArgs) => void,
period: number,
)
=> number;
declare const clearTimeout: (timeoutId: number | undefined) => void;