/**
* Receives an array, like Promise.all, and runs until the first rejection.
*
* Unlike Promise.all, but like Promise.allSettled, this will always resolve
* to an object; however, like Promise.all, this will resolve as soon as it
* encounters the first rejection.
*
* Returns a promise that resolves to an object with these properties:
* success: boolean, whether Promise.all would have succeeded
* count: number, number of resolved Promises at the time of return
* results: Array, result array containing all resolved Promises/values
* error: any, the reject value that caused this to fail, or null
*/
function allWithProgress(arrayOfPromises) {
const results = new Array(arrayOfPromises);
let count = 0;
/**
* Given an input to Promise.resolve, increments results+count
* when complete.
*/
function wrap(valueOrThenable, index) {
return Promise.resolve(valueOrThenable).then(x => {
results[index] = x;
count++;
return x;
});
}
// slice(0) prevents the results array from being modified.
// You could also add a condition check that prevents `wrap` from
// modifying the results after it returns.
return Promise
.all(arrayOfPromises.map(wrap)) // or "(e, i) => wrap(e, i)"
.then(x => ({success: true, count, results: results.slice(0), error: null}))
.catch(e => ({success: false, count, results: results.slice(0), error: e}));
}
// Test harness below
function timeoutPromise(string, timeoutMs) {
console.log("Promise created: " + string + " - " + timeoutMs + "ms");
return new Promise(function(resolve, reject) {
window.setTimeout(function() {
console.log("Promise resolved: " + string + " - " + timeoutMs + "ms");
resolve(string);
}, timeoutMs);
});
}
Promise.resolve().then(() => {
// success
return allWithProgress([
timeoutPromise("s1", 1000),
timeoutPromise("s2", 2000),
timeoutPromise("s3", 3000),
"not a promise"
]).then(console.log);
}).then(() => {
// failure
return allWithProgress([
timeoutPromise("f1", 1000),
timeoutPromise("f2", 2000)
// rejects with a String for Stack Snippets; use an Error in real code
.then(() => Promise.reject("f2 failed")),
timeoutPromise("f3", 3000),
"not a promise"
]).then(console.log);
});