/** * 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(promises: Promise[], predicate?: (value: T) => Error | null): Promise { 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), ); }