Skip to content

Instantly share code, notes, and snippets.

@stropitek
Created January 11, 2021 09:57
Show Gist options
  • Save stropitek/a2cf7f311cae4cf863192bcc9fc4c827 to your computer and use it in GitHub Desktop.
Save stropitek/a2cf7f311cae4cf863192bcc9fc4c827 to your computer and use it in GitHub Desktop.
Debounce function execution
// Not using recursive types because it is recommend to use those carefully
// for performance reasons
type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
// debounce function which resolves with undefined when call has been cancelled
// The function returns a promise which resolves with awaited return value of the callback
// Except if the callback call was canceled because of the debouncing in which case
// the promise resolves with undefined
export default function debounce<T>(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
func: (...args: any[]) => T,
wait: number,
) {
let timeout: NodeJS.Timeout | null = null;
let _resolve: (
value: Awaited<T | undefined> | PromiseLike<Awaited<T>>,
) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return function (this: any, ...args: any[]) {
return new Promise<Awaited<T> | undefined>((resolve, reject) => {
if (timeout) {
if (_resolve) {
// Debounced function called again before timeout passed
// The previous call resolves with undefined
_resolve(undefined);
}
clearTimeout(timeout);
}
_resolve = resolve;
timeout = setTimeout(() => {
timeout = null;
try {
// @ts-expect-error nested promise
resolve(func.apply(this, args));
} catch (e) {
reject(e);
}
}, wait);
});
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment