Created
November 10, 2020 19:04
-
-
Save stefcameron/c0869b8ea988492187afaa65c0ba3dce to your computer and use it in GitHub Desktop.
A promise that (always) resolves only once ALL given promises have resolved or rejected (requires ES6)
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
/** | |
* [ASYNC] Waits for every promise to either resolve or reject, which is different | |
* from `Promise.all()` which rejects on the first rejection __without waiting | |
* for other promises to settle__. | |
* @param {Array<Promise>} promises | |
* @returns {Promise<{ results: Array, errors: Array}>} An object where `results` | |
* are the settled values of all resolved promises, in the order in which they | |
* appeared in `promises` (but not necessarily sequential if there were rejections), | |
* and `errors` are the settled values of all rejected promises, in the order | |
* in which they appeared in `promises` (again, not necessarily sequential). | |
* Either array will be empty if there were no resolutions/rejections, respectively. | |
* | |
* NOTE: This Promise does NOT reject. It always resolves. Errors, if any, are | |
* provided in the resolved object. | |
*/ | |
export const every = function (promises) { | |
return new Promise(function (resolve) { | |
const output = { results: [], errors: [] }; | |
// resolve immediately if we have nothing to monitor | |
if (promises.length <= 0) { | |
return resolve(output); | |
} | |
// keys are promises, values are null until either fulfilled or rejected; | |
// when fulfilled, `{ result: any}`, when rejected, `{ error: any }`. | |
// NOTE: keys in a Map are ordered in the order of insertion | |
const map = new Map(promises.map((promise) => [promise, null])); | |
let remainder = promises.length; | |
const finish = function () { | |
remainder--; | |
if (remainder <= 0) { | |
for (const res of map.values()) { | |
// NOTE: property value will be `undefined` if the promise didn't | |
// resolve to anything, or reject with anything | |
if (Object.prototype.hasOwnProperty.call(res, 'result')) { | |
output.results.push(res.result); | |
} else { | |
output.errors.push(res.error); | |
} | |
} | |
resolve(output); | |
} | |
}; | |
promises.forEach((promise) => { | |
promise | |
.then((result) => map.set(promise, { result })) | |
.catch((error) => map.set(promise, { error })) | |
.finally(finish); | |
}); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment