Handling Parallel Requests and Partial Failures in Axios
When building modern web applications, executing multiple HTTP
requests concurrently can significantly improve performance. However,
standard methods like Promise.all() terminate early if even
a single request fails, dropping the data from successful calls. This
article explains how to execute parallel requests using Axios and handle
partial failures gracefully using Promise.allSettled() and
inline error-catching strategies.
The Limitation of
Promise.all()
The standard way to run asynchronous operations in parallel in
JavaScript is Promise.all(). While efficient,
Promise.all() has a "fail-fast" mechanism:
// If any request fails, the entire block jumps to the catch handler
try {
const [users, posts] = await Promise.all([
axios.get('/api/users'),
axios.get('/api/posts')
]);
} catch (error) {
// You lose access to the successful request's data
console.error("One or more requests failed", error);
}If /api/posts returns a 500 error, the successful
response from /api/users is lost within the catch
block.
Method 1: Using
Promise.allSettled() (Recommended)
ES2020 introduced Promise.allSettled(), which waits for
all promises to finish regardless of whether they resolve or reject. It
returns an array of objects describing the outcome of each promise.
Implementation
import axios from 'axios';
async function fetchDashboardData() {
const userPromise = axios.get('https://api.example.com/users');
const postPromise = axios.get('https://api.example.com/posts');
const notificationPromise = axios.get('https://api.example.com/notifications');
const results = await Promise.allSettled([
userPromise,
postPromise,
notificationPromise
]);
const [usersResult, postsResult, notificationsResult] = results;
// Process Users
if (usersResult.status === 'fulfilled') {
console.log('Users Data:', usersResult.value.data);
} else {
console.error('Users request failed:', usersResult.reason.message);
}
// Process Posts
if (postsResult.status === 'fulfilled') {
console.log('Posts Data:', postsResult.value.data);
} else {
console.error('Posts request failed:', postsResult.reason.message);
}
// Process Notifications
if (notificationsResult.status === 'fulfilled') {
console.log('Notifications Data:', notificationsResult.value.data);
} else {
console.error('Notifications request failed:', notificationsResult.reason.message);
}
}Each result object contains:
status: Either'fulfilled'or'rejected'.value: The Axios response object (present only iffulfilled).reason: The Axios error object (present only ifrejected).
Method 2: Inline
Catch Handlers with Promise.all()
If you are working in an environment that lacks
Promise.allSettled() support, you can attach an individual
.catch() handler to each Axios call inside a
Promise.all() array. This prevents errors from bubbling up
and rejecting the parent promise.
Implementation
import axios from 'axios';
async function fetchAnalytics() {
const [metrics, logs] = await Promise.all([
axios.get('/api/metrics').catch((err) => ({ error: true, details: err })),
axios.get('/api/logs').catch((err) => ({ error: true, details: err }))
]);
if (metrics.error) {
console.warn('Metrics failed to load:', metrics.details.message);
} else {
console.log('Metrics:', metrics.data);
}
if (logs.error) {
console.warn('Logs failed to load:', logs.details.message);
} else {
console.log('Logs:', logs.data);
}
}By returning a fallback value or an error wrapper object in the
.catch() block, the promise resolves successfully, allowing
Promise.all() to complete.
Summary Checklist
- Use
Promise.allSettled()as the primary solution for parallel calls where each request's state needs independent evaluation. - Inspect the
statusproperty (fulfilledvs.rejected) before attempting to accessresult.value.data. - Use inline
.catch()blocks if you prefer defining default fallback data directly inside the request declaration.