Skip to content

@briancavalier /whenN.js
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fan-in promise resolution
// Return a promise that will resolve when and only
// when N of the supplied promises resolve. The
// resolution value will be an array containing the
// resolution values of the triggering promises.
// TODO: Figure out the best strategy for rejecting.
function whenN(n, promises) {
var toResolve, values, promise;
toResolve = Math.max(0, Math.min(n, promises.length));
values = [];
promise = new Promise();
// Resolver for promises. Captures the value and resolves
// the returned promise when toResolve reaches zero.
// Overwrites resolver var with a noop once promise has
// be resolved to cover case where n < promises.length
function resolver(val) {
values.push(val);
if(--toResolve === 0) {
resolver = noop;
promise.resolve(values);
}
}
// Wrapper so that resolver can be replaced
function resolve(val) {
resolver(val);
}
// Rejecter for promises. Rejects returned promise
// immediately, and overwrites rejecter var with a noop
// once promise to cover case where n < promises.length.
// TODO: Consider rejecting only when N (or promises.length - N?)
// promises have been rejected instead of only one?
function rejecter(err) {
rejecter = noop;
promise.reject(err);
}
// Wrapper so that rejecer can be replaced
function reject(err) {
rejecter(err);
}
for (var i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
return promise;
}
function whenAll(promises) {
return whenN(promises.length, promises);
}
function whenAny(promises) {
return whenN(1, promises);
}
@unscriptable

Nice! I've been meaning to write this for a while now! Need to think about the reject use cases as you noted.

@unscriptable

Just glancing at this code... If I am not mistaken, for any case where n < promises.length or if any promise calls reject(), then you'll get errors because the promise could get completed (resolved/rejected) more than once.

@briancavalier

Yeah, you're absolutely right, I need to guard against that. I've been thinking about how to use function replacement/rewriting once the resolve/reject has fired.

@briancavalier

Here's a quick attempt at a version that uses function replacement to avoid the reject problem. I also applied the same pattern to resolving. Def more verbose, but seems decent. I tested resolving, but haven't tested rejecting yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.