What is the difference between promise.all and promise.allsettled?
Promise.all rejects the moment any promise in the array rejects. Promise.allSettled always resolves, collecting a result from every promise regardless of whether it succeeded or failed.
Theory
TL;DR
Promise.allis like a restaurant order for the whole table: one dish gets cancelled, the entire order is cancelled.Promise.allSettledtracks each dish separately.Promise.allshort-circuits on the first rejection and discards the rest.Promise.allSettledalways resolves with[{status, value}, {status, reason}, ...].- Need every result before moving on? Use
all. Need to track all outcomes no matter what? UseallSettled. - Both preserve input order, not settle order.
Quick example
const p1 = Promise.resolve('user data');
const p2 = Promise.reject('DB error');
const p3 = new Promise(resolve => setTimeout(() => resolve('cache data'), 100));
// Bails on p2, p3 result is discarded
Promise.all([p1, p2, p3]).catch(err => console.log('all:', err));
// Output: all: DB error
// Waits for all three, always resolves
Promise.allSettled([p1, p2, p3]).then(results => console.log(results));
// Output:
// [
// { status: 'fulfilled', value: 'user data' },
// { status: 'rejected', reason: 'DB error' },
// { status: 'fulfilled', value: 'cache data' }
// ]When p2 rejects, Promise.all stops caring about p3. Promise.allSettled collects all three and resolves normally.
Key difference
Promise.all returns plain values in an array, but only when every promise fulfills. The first rejection triggers the outer promise to reject with that same error. The remaining promises still run to completion, their results are just ignored. Promise.allSettled never rejects. It resolves with an array of objects, each with a status field set to 'fulfilled' or 'rejected', plus either value or reason.
When to use
- All results are required before moving on (fetching data for every widget on a dashboard):
Promise.all - Partial failures are acceptable (batch image uploads, sending analytics events):
Promise.allSettled - You need to log or audit every outcome, including failures:
Promise.allSettled - Operations depend on each other (need user data before fetching permissions):
Promise.all - You want to always respond to the client, even when some requests fail:
Promise.allSettled
Comparison table
| Feature | Promise.all | Promise.allSettled |
|---|---|---|
| Resolves when | All promises fulfill | All promises settle |
| Rejects when | Any promise rejects | Never |
| Return value | Array of values | Array of {status, value/reason} |
| Order preserved | Yes | Yes |
| Empty array input | Resolves [] | Resolves [] |
| Non-promise values | Treated as resolved | Treated as resolved |
| Typical use case | Critical batch operations | Health checks, bulk uploads |
How it works internally
Both methods iterate the input and track a counter of pending promises. Promise.all attaches a single rejection handler that fires on the first failure and ignores everything else. Promise.allSettled attaches both .then() and .catch() to each promise individually, pushing a status object to the results array on every settle. When the counter hits zero, the outer promise resolves with the full array. Both follow the same spec since ES2020 and are available from Node.js 12.9+.
Common mistakes
Expecting Promise.all to give partial results
// Wrong: .then() never fires if rejectingP rejects
Promise.all([p1, rejectingP, p3])
.then(results => console.log(results));
// Fix: switch to allSettled and filter
Promise.allSettled([p1, rejectingP, p3])
.then(results => results
.filter(r => r.status === 'fulfilled')
.map(r => r.value)
);Forgetting that allSettled wraps results in objects
// Wrong: result is an object, not the actual value
for (const result of await Promise.allSettled(promises)) {
processData(result); // passes {status, value} instead of the data
}
// Fix: check status before accessing the value
for (const result of await Promise.allSettled(promises)) {
if (result.status === 'fulfilled') processData(result.value);
else logError(result.reason);
}Using allSettled when operations depend on each other
// Wrong: continues with undefined if fetchUser fails
const results = await Promise.allSettled([fetchUser(id), fetchPermissions(id)]);
const user = results[0].value; // undefined if rejected
renderDashboard(user); // crashes
// Fix: for dependent data, use Promise.all
const [user, permissions] = await Promise.all([fetchUser(id), fetchPermissions(id)]);Passing non-promise values without knowing the behavior
// Works, but mixing types hides intent
Promise.all([1, 'hello', fetch('/api/data')]);
// 1 and 'hello' become Promise.resolve(1) and Promise.resolve('hello')
// Be explicit about what you're running concurrentlyReal-world usage
- React Query:
useQueriesusesallSettledinternally so each query has its own loading and error state - Next.js:
getStaticPathsfallback logic during build-time usesallSettled - Express batch endpoints:
allSettledto always send a response, even when some DB queries fail - Puppeteer:
allSettledfor page scraping when some selectors may not exist on every page - Node.js CLI tools:
allSettledfor bulk file reads where some files might be missing
Follow-up questions
Q: What happens when you pass an empty array to either method?
A: Both resolve immediately with []. No rejection, no waiting.
Q: What if the array contains a plain value like a number instead of a promise?
A: Both coerce it to Promise.resolve(value). With allSettled, it shows as {status: 'fulfilled', value: number}.
Q: Does the output order match the input order?
A: Yes, always. The order reflects the input array, not which promise settled first.
Q: How does Promise.any() differ from these two?
A: Promise.any() resolves as soon as the first promise fulfills and rejects only if every promise rejects. Promise.allSettled always waits for everything and never rejects.
Q (senior): How would you polyfill Promise.allSettled for environments without native support?
A: Wrap each promise with .then(value => ({status: 'fulfilled', value})).catch(reason => ({status: 'rejected', reason})), then pass the array to Promise.all. Each wrapper always fulfills, so Promise.all never rejects and you get back the same shape as allSettled.
Examples
Fetching data for multiple API endpoints
const userIds = [1, 2, 3];
try {
const users = await Promise.all(
userIds.map(id => fetch(`/api/users/${id}`).then(r => r.json()))
);
console.log(users); // [user1, user2, user3]
} catch (err) {
// One fetch failed, nothing rendered
console.error('Fetch failed:', err);
}Use this when all data is required before rendering. If user 2 is missing, showing the others could mislead the user about what data is actually available.
Express batch endpoint with partial success
app.get('/batch/users', async (req, res) => {
const ids = req.query.ids.split(',');
const results = await Promise.allSettled(
ids.map(id => fetchUserFromDB(id))
);
const found = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
const failed = results
.filter(r => r.status === 'rejected')
.map((r, i) => ({ id: ids[i], error: r.reason.message }));
res.json({ found, failed });
// Always responds, even when some DB queries fail
});The client always gets a response and knows exactly which IDs worked and which did not. This pattern comes up often in admin tools and batch-action APIs.
Bulk file reads with error tracking
const fs = require('fs').promises;
const filePaths = ['./data/a.json', './data/b.json', './data/missing.json'];
const results = await Promise.allSettled(
filePaths.map(path => fs.readFile(path, 'utf-8').then(JSON.parse))
);
results.forEach((result, i) => {
if (result.status === 'fulfilled') {
console.log(`Loaded ${filePaths[i]}:`, result.value);
} else {
console.warn(`Skipped ${filePaths[i]}:`, result.reason.message);
}
});
// Processes a.json and b.json, logs a warning for missing.jsonI've used this in data migration scripts where some source files are optional. With Promise.all, a single missing file would abort the entire run. Promise.allSettled processes everything it can and tells you what failed.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.