Skip to content

Instantly share code, notes, and snippets.

@mathiasschopmans
Created November 13, 2024 14:09
Show Gist options
  • Save mathiasschopmans/e33ec5e6528657471341712f9d39e1ce to your computer and use it in GitHub Desktop.
Save mathiasschopmans/e33ec5e6528657471341712f9d39e1ce to your computer and use it in GitHub Desktop.
Async TypeScript helpers
/**
* Creates a debounced version of an asynchronous function that delays the execution
* of the function until after `wait` milliseconds have elapsed since the last time it was invoked.
*
* @template Args - The argument types of the function being debounced.
* @template R - The return type of the function being debounced.
*
* @param {(...args: Args) => Promise<R>} func - The asynchronous function to debounce.
* @param {number} [wait=150] - The number of milliseconds to delay; defaults to 150ms.
* @returns {(...args: Args) => Promise<R>} - A debounced version of the function that returns a promise.
*
* @example
* const debouncedFunction = debounce(asyncFunction, 200);
* debouncedFunction(arg1, arg2)
* .then(result => {
* // handle result
* })
* .catch(error => {
* // handle error
* });
*/
export function debounce<Args extends unknown[], R>(
func: (...args: Args) => Promise<R>,
wait: number = 150,
): (...args: Args) => Promise<R> {
let timeout: ReturnType<typeof setTimeout> | undefined;
return (...args: Args): Promise<R> => {
return new Promise((resolve, reject) => {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func(...args)
.then(resolve)
.catch(reject);
}, wait);
});
};
}
/**
* Memoizes an asynchronous function, caching resolved promises by argument key.
* Only caches successful results; failed promises are not stored.
*
* @template Args - The arguments passed to the function, must be serializable.
* @template R - The return type of the resolved promise.
* @param {(...args: Args) => Promise<R>} func - The asynchronous function to memoize.
* @returns {(...args: Args) => Promise<R>} A memoized version of the provided function that caches resolved results.
*
* @example
* async function fetchData(id) {
* // ... fetch logic
* }
* const memoizedFetchData = memoize(fetchData);
* memoizedFetchData(1).then(data => console.log(data)); // Fetches and caches the result
* memoizedFetchData(1).then(data => console.log(data)); // Returns cached result
*/
export function memoize<Args extends unknown[], R>(
func: (...args: Args) => Promise<R>,
): (...args: Args) => Promise<R> {
const cache = new Map<string, Promise<R>>();
return (...args: Args): Promise<R> => {
const key = JSON.stringify(args); // Assumes that args are serializable
if (cache.has(key)) {
return cache.get(key)!;
}
const promise = func(...args)
.then((result) => {
cache.set(key, Promise.resolve(result)); // Cache only successful results
return result;
})
.catch((error) => {
cache.delete(key); // Remove failed promises from cache
throw error;
});
cache.set(key, promise);
return promise;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment