Reputation: 9790
Before starting an express server JS I want to make three API calls. If any one of them fails I just want to log an error, but if all three fail I want to throw an error and prevent the server from starting.
I have seen I can use Promise.all
, but I am unsure how to handle the case if one fails. Using the code below if any fail the error will be thrown. How can I limit this to only occurring if all calls fail?
const fetchNames = async () => {
try {
await Promise.all([
axios.get("./one.json"),
axios.get("./two.json"),
axios.get("./three.json")
]);
} catch {
throw Error("Promise failed");
}
};
Upvotes: 0
Views: 994
Reputation: 664217
If you need just any of the results, Promise.any
will work for this use case - it'll reject only if all promises reject.
const value = await Promise.any([
axios.get("./one.json").catch(err => { console.log(err); throw err; }),
axios.get("./two.json").catch(err => { console.log(err); throw err; }),
axios.get("./three.json").catch(err => { console.log(err); throw err; }),
]);
If you need all result values from the promises that did happen to fulfill, use Promise.allSettled
.
const results = await Promise.allSettled([
axios.get("./one.json"),
axios.get("./two.json"),
axios.get("./three.json"),
]);
const values = [], errors = [];
for (const result of results) {
if (result.status === 'fulfilled') {
values.push(result.value);
} else { // result.status === 'rejected'
errors.push(result.reason);
}
}
if (!values.length) {
throw new AggregateError(errors);
} else {
for (const err of errors) {
console.log(err);
}
// do stuff with values
}
Upvotes: 1
Reputation: 26861
If I understand correctly, you're actually interested in not having the catch(e){...}
executed if any of them worked, right? then you can do this:
const fetchNames = async () => {
try {
await Promise.all([
axios.get("./one.json").catch(e => console.log(`one failed`, e)),
axios.get("./two.json").catch(e => console.log(`two failed`, e)),
axios.get("./three.json").catch(e => console.log(`three failed`, e))
]);
} catch {
throw Error("Promise failed");
}
};
The problem above is that if all of them fail, then no error is thrown. If you're also interested in that, then something like this should work:
const fetchNames = async () => {
try {
let success = false;
await Promise.all([
axios.get("./one.json").then( () => success = true).catch(e => console.log(`one failed`, e)),
axios.get("./two.json").then( () => success = true).catch(e => console.log(`two failed`, e)),
axios.get("./three.json").then( () => success = true).catch(e => console.log(`three failed`, e))
]);
if (!success) throw new Error(`No successful promises`);
} catch {
throw Error("Promise failed");
}
};
Upvotes: -1
Reputation: 370659
If you don't need the fulfillment values, or need just any of them, Promise.any
will work for this use case - it'll reject only if all Promises reject.
const firstResolveValue = await Promise.any([
axios.get("./one.json"),
axios.get("./two.json"),
axios.get("./three.json")
]);
If you need all result values from the Promises that happen to fulfill, use Promise.allSettled
.
const settledResults = await Promise.allSettled([
axios.get("./one.json"),
axios.get("./two.json"),
axios.get("./three.json")
]);
const fulfilledResults = settledResults.filter(result => result.status === 'fulfilled');
if (!fulfilledResults.length) {
throw new Error();
} else {
// do stuff with fulfilledResults
}
Upvotes: 3