@ugo-code/streamline.js
Version:
A utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript
54 lines (53 loc) • 2.46 kB
TypeScript
/**
* A serializable value that can be used as a key. It can be a primitive,
* a plain object, or an array that can be safely stringified with JSON.
*/
type SerializableKey = unknown;
/**
* Ensures that an asynchronous task is only executed once at a time for a given key.
*
* If this function is called while a task with the same key is already running,
* it will return the promise of the existing task instead of starting a new one.
* This is useful for preventing duplicate network requests or other expensive
* operations. Once a task is complete (either resolves or rejects), its promise is
* removed, and the next call with the same key will trigger a new execution.
*
* @template TResult The expected result type of the asynchronous task.
* @param {() => Promise<TResult>} taskFn The asynchronous function to execute.
* @param {SerializableKey} [key] An optional unique identifier for the task.
* If it's an object or array, it will be JSON-stringified and hashed.
* If not provided, the task function's source code (`taskFn.toString()`) is
* hashed to generate a key. Note that this may not be unique for different
* function instances with identical source code.
* @returns {Promise<TResult>} A promise that resolves or rejects with the result of the task.
* @example
* ```ts
* // Example 1: Basic deduplication with a string key
* async function fetchUser(userId: string) {
* // This function will only be executed once, even if called multiple times in parallel.
* return singleExecution(
* () => {
* console.log(`Fetching user ${userId}...`);
* return api.fetch(`/users/${userId}`);
* },
* `user-${userId}` // A simple, descriptive key
* );
* }
*
* Promise.all([fetchUser('123'), fetchUser('123')]); // "Fetching user 123..." is logged only once.
*
* // Example 2: Using an object as a key
* async function searchProducts(filters: object) {
* return singleExecution(
* () => api.post('/products/search', filters),
* filters // The filters object is hashed to create a unique key
* );
* }
*
* // Example 3: No key provided (hashes the function's source)
* const fetchConfig = () => singleExecution(() => api.fetch('/config'));
* Promise.all([fetchConfig(), fetchConfig()]); // The config is fetched only once.
* ```
*/
export declare function singleExecution<TResult>(taskFn: () => Promise<TResult>, key?: SerializableKey): Promise<TResult>;
export {};