Skip to content

Instantly share code, notes, and snippets.

@mazesoul
Last active March 24, 2017 18:08
Show Gist options
  • Save mazesoul/0b9319a2cc30d171b4cb00783d0bd93c to your computer and use it in GitHub Desktop.
Save mazesoul/0b9319a2cc30d171b4cb00783d0bd93c to your computer and use it in GitHub Desktop.
Debounced promise with multiple context
/**
* Laurent Villleneuve 2017-03-24
* https://github.com/mazesoul
*
* Uses Q.js but should be transposable.
*
* Debounces the execution of a function, not by time but by its returning promise
*
* 1. On first call, invoke the <debounced> function, store and return its promise.
* 2. Subsequent calls return the first call's promise
* 3. When the first call promise is resolved, the debouncing context is over. (Instead of a timeout)
*
* This allows multiple concurrent calls to rely on the successful execution of a single method.
*
* Example:
*
* If multiple calls come in that all require a default value. And this value generation has some lag (db state).
* When the calls are initiated, they all cannot find the default value. Consequently they all attempt to create it.
* This lead to multiple instances of a default value which is undesirable.
* (Or, to failures if duplication constraints are in place)
*
* This wrapper ensures that only the first caller invokes the default value generation.
* Subsequent calls return the first call's promise without duplicating the execution.
*
*
* @param {function} options.concurrencyId A function that generates a concurrencyId to identify concurrent calls.
* The function is invoked with the same arguments as <debounced>.
* PS: The same function could be necessary in multiple context that are not concurrent. (Multiple tenants)
* @param {[type]} options.debounced A function that returns a promise and needs to be debounced.
* @return {[type]} [description]
*/
function debouncedPromise({concurrencyId,debounced}) {
const pendings = new Map();
return (...args) => {
const key = concurrencyId(...args);
if (pendings.has(key)) {
return pendings.get(key);
}
const deferred = Q.defer();
pendings.set(key, deferred.promise);
deferred.resolve(debounced(...args));
return deferred.promise.finally(() => pendings.delete(key));
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment