JavaScript Promises: all, allSettled, any and race Explained
await in a loop runs requests one after another. JavaScript's promise combinators let you run them together and decide how to handle failures.
Sequential vs parallel
// Slow: each request waits for the previous one
for (const id of ids) {
results.push(await fetchUser(id));
}
// Fast: all requests in flight at once
const results = await Promise.all(ids.map(fetchUser));
Promise.all: all or nothing
Resolves with every result in order, or rejects as soon as one fails. Use it when you need all results to continue.
const [user, orders, settings] = await Promise.all([getUser(id), getOrders(id), getSettings(id)]);
Promise.allSettled: keep going on failures
const results = await Promise.allSettled(emails.map(sendEmail));
const failed = results.filter((r) => r.status === 'rejected');
console.log(`${results.length - failed.length} sent, ${failed.length} failed`);
Promise.any: first success wins
// Try several mirrors, use whichever answers first successfully
const res = await Promise.any(mirrors.map((url) => fetch(url)));
// Rejects with an AggregateError only if ALL fail
Promise.race: first to settle wins
const timeout = (ms) => new Promise((_, reject) => setTimeout(() => reject(new Error('Timed out')), ms));
const data = await Promise.race([fetchReport(), timeout(5000)]);
For fetch, AbortSignal.timeout(5000) is better because it actually cancels the request.
Limiting concurrency
Promise.all on 10,000 items fires 10,000 requests at once. Process in limited batches instead:
async function mapWithLimit(items, limit, fn) {
const results = new Array(items.length);
let next = 0;
async function worker() {
while (next < items.length) {
const i = next++;
results[i] = await fn(items[i], i);
}
}
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
return results;
}
const users = await mapWithLimit(ids, 5, fetchUser); // at most 5 at a time
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.