Skip to content

Instantly share code, notes, and snippets.

@sam-w
Created August 5, 2019 03:16
Show Gist options
  • Save sam-w/247667eac389b446af9e1bc54398e67a to your computer and use it in GitHub Desktop.
Save sam-w/247667eac389b446af9e1bc54398e67a to your computer and use it in GitHub Desktop.
/**
* Executes a list of Promises in parallel and resolves with the first successful resolution.
*
* Like `Promise.race` in that it takes a list of Promises and only waits for the first completion, but
* differs in that it requires a _successful_ resolution before it completes. Only rejects if _all_ children reject.
*
* Different
* @param promises a list of promises to resolve.
* @param where an optional predicate. Any Promise `p` which resolves but for which the predicate
* produces an error will behave as `p` instead rejected.
*/
// Do not let tslint convert this to async. It will get it wrong and change the behaviour.
// tslint:disable-next-line: array-type
function firstSuccess<T>(promises: Promise<T>[], predicate?: (value: T) => Error | null): Promise<T> {
return Promise.all(promises.map((p) => {
// If a request fails, count that as a resolution so it will keep
// waiting for other possible successes. If a request succeeds,
// treat it as a rejection so Promise.all immediately bails out.
return p.then(
(val) => {
const e = predicate && predicate(val);
return e ? Promise.resolve(e) : Promise.reject(val);
},
(err) => Promise.resolve(err),
);
})).then(
// If '.all' resolved, we've just got an array of errors.
(errors) => Promise.reject(errors),
// If '.all' rejected, we've got the result we wanted.
(val) => Promise.resolve(val),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment