Let\'s say I have a set of Promise
s that are making network requests, of which one will fail:
// http://does-not-exist will throw a TypeError
va
I've been using following codes since ES5.
Promise.wait = function(promiseQueue){
if( !Array.isArray(promiseQueue) ){
return Promise.reject('Given parameter is not an array!');
}
if( promiseQueue.length === 0 ){
return Promise.resolve([]);
}
return new Promise((resolve, reject) =>{
let _pQueue=[], _rQueue=[], _readyCount=false;
promiseQueue.forEach((_promise, idx) =>{
// Create a status info object
_rQueue.push({rejected:false, seq:idx, result:null});
_pQueue.push(Promise.resolve(_promise));
});
_pQueue.forEach((_promise, idx)=>{
let item = _rQueue[idx];
_promise.then(
(result)=>{
item.resolved = true;
item.result = result;
},
(error)=>{
item.resolved = false;
item.result = error;
}
).then(()=>{
_readyCount++;
if ( _rQueue.length === _readyCount ) {
let result = true;
_rQueue.forEach((item)=>{result=result&&item.resolved;});
(result?resolve:reject)(_rQueue);
}
});
});
});
};
The usage signature is just like Promise.all
. The major difference is that Promise.wait
will wait for all the promises to finish their jobs.
Promise.all
with using modern async/await
approach
const promise1 = //...
const promise2 = //...
const data = await Promise.all([promise1, promise2])
const dataFromPromise1 = data[0]
const dataFromPromise2 = data[1]
This should be consistent with how Q does it:
if(!Promise.allSettled) {
Promise.allSettled = function (promises) {
return Promise.all(promises.map(p => Promise.resolve(p).then(v => ({
state: 'fulfilled',
value: v,
}), r => ({
state: 'rejected',
reason: r,
}))));
};
}
There is a finished proposal for a function which can accomplish this natively, in vanilla Javascript: Promise.allSettled
, which has made it to stage 4, is officialized in ES2020, and is implemented in all modern environments. It is very similar to the reflect
function in this other answer. Here's an example, from the proposal page. Before, you would have had to do:
function reflect(promise) {
return promise.then(
(v) => {
return { status: 'fulfilled', value: v };
},
(error) => {
return { status: 'rejected', reason: error };
}
);
}
const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.all(promises.map(reflect));
const successfulPromises = results.filter(p => p.status === 'fulfilled');
Using Promise.allSettled
instead, the above will be equivalent to:
const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.allSettled(promises);
const successfulPromises = results.filter(p => p.status === 'fulfilled');
Those using modern environments will be able to use this method without any libraries. In those, the following snippet should run without problems:
Promise.allSettled([
Promise.resolve('a'),
Promise.reject('b')
])
.then(console.log);
Output:
[
{
"status": "fulfilled",
"value": "a"
},
{
"status": "rejected",
"reason": "b"
}
]
For older browsers, there is a spec-compliant polyfill here.
var err;
Promise.all([
promiseOne().catch(function(error) { err = error;}),
promiseTwo().catch(function(error) { err = error;})
]).then(function() {
if (err) {
throw err;
}
});
The Promise.all
will swallow any rejected promise and store the error in a variable, so it will return when all of the promises have resolved. Then you can re-throw the error out, or do whatever. In this way, I guess you would get out the last rejection instead of the first one.
I had the same problem and have solved it in the following way:
const fetch = (url) => {
return node-fetch(url)
.then(result => result.json())
.catch((e) => {
return new Promise((resolve) => setTimeout(() => resolve(fetch(url)), timeout));
});
};
tasks = [fetch(url1), fetch(url2) ....];
Promise.all(tasks).then(......)
In that case Promise.all
will wait for every Promise will come into resolved
or rejected
state.
And having this solution we are "stopping catch
execution" in a non-blocking way. In fact, we're not stopping anything, we just returning back the Promise
in a pending state which returns another Promise
when it's resolved after the timeout.