Created
August 5, 2019 03:16
-
-
Save sam-w/247667eac389b446af9e1bc54398e67a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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