← Back to JavaScript Course | Chapter 4: Modern JS, Async & DOM | Lesson 24 of 26

JS Async Parallel

Awaiting several independent async operations one after another wastes time unnecessarily, when they could run at the same time instead -- Promise.all() (and its relatives) let you kick off multiple async operations in parallel and wait for all of them together, dramatically reducing total wait time.

The Problem with Sequential Awaiting

Awaiting one async operation, then starting and awaiting the next, and so on, means the TOTAL time is the SUM of every individual operation's time -- if three independent operations each take one second, sequential awaiting takes three seconds total, even though none of them actually depended on each other.

Note: Before awaiting several operations one after another, ask whether any of them actually depend on a previous one's result -- if not, they are strong candidates for running in parallel instead.

Warning: Sequentially awaiting operations that have no actual dependency on each other is a common, easy-to-miss performance mistake in async code.

Example: The Problem with Sequential Awaiting

javascript
async function sequential() {
  const a = await new Promise(r => setTimeout(() => r(1), 1000));
  const b = await new Promise(r => setTimeout(() => r(2), 1000));
  console.log(a, b); // takes ~2 seconds total
}
sequential();

Running in Parallel with Promise.all()

Promise.all([promise1, promise2, ...]) starts every promise in the array immediately (they run concurrently, not one after another), and resolves once all of them have succeeded, with an array of their results in the same order they were passed in.

Note: Start every independent async operation first (without awaiting each individually), collect them into an array, and pass that array to Promise.all() to run them together.

Warning: Promise.all() rejects immediately the moment ANY single promise in the array rejects, even if the others are still pending -- you lose visibility into whichever of the others might have succeeded.

Example: Running in Parallel with Promise.all()

javascript
async function parallel() {
  const [a, b] = await Promise.all([
    new Promise(r => setTimeout(() => r(1), 1000)),
    new Promise(r => setTimeout(() => r(2), 1000)),
  ]);
  console.log(a, b); // takes ~1 second total
}
parallel();

Handling Partial Failures with Promise.allSettled()

Unlike Promise.all(), Promise.allSettled() always waits for every promise to finish, regardless of individual success or failure -- each result in the returned array has a status field ("fulfilled" or "rejected") plus either a value or a reason, letting you handle mixed outcomes gracefully.

Note: Use Promise.allSettled() specifically when partial failure is acceptable and you want to know the outcome of every operation, not just fail everything at the first rejection.

Warning: Promise.allSettled() never itself rejects -- checking each individual result's status field is necessary to detect any failures among the group.

Example: Handling Partial Failures with Promise.allSettled()

javascript
Promise.allSettled([
  Promise.resolve(1),
  Promise.reject("failed"),
]).then(results => console.log(results));

Racing Operations with Promise.race()

Promise.race([promise1, promise2, ...]) settles (resolves or rejects) as soon as the FIRST promise in the array settles, ignoring whatever the others eventually do -- commonly used to implement a timeout, racing a real operation against a promise that rejects after a fixed delay.

Note: Use Promise.race() to implement a timeout: race your actual operation against a promise that rejects after your desired timeout duration.

Warning: Promise.race() only reports the FIRST settled promise -- the others continue running in the background even though their eventual result is ignored, which is worth being aware of for cleanup purposes.

Example: Racing Operations with Promise.race()

javascript
Promise.race([
  new Promise(r => setTimeout(() => r("data"), 100)),
  new Promise((_, reject) => setTimeout(() => reject("timeout"), 50)),
]).then(console.log).catch(console.log);

Choosing the Right Combinator

Promise.all() is right when every operation must succeed for the overall result to be meaningful; Promise.allSettled() is right when partial success is acceptable and you want visibility into every outcome; Promise.race() is right for a "whichever finishes first" scenario like a timeout.

Note: Match the combinator to the actual failure semantics you need: all-or-nothing (all), best-effort (allSettled), or first-to-finish (race).

Warning: Choosing Promise.all() for a scenario where partial success should be acceptable throws away the results of every operation that succeeded, just because one other operation failed.

Example: Choosing the Right Combinator

javascript
Promise.all([Promise.resolve(1), Promise.resolve(2)]).then(r => console.log("all:", r));
Promise.allSettled([Promise.resolve(1), Promise.reject("x")]).then(r => console.log("settled:", r));
Common Mistakes
  1. Awaiting several independent promises sequentially with separate await statements, one after another, when starting them all at once and awaiting together would take a fraction of the time.
  2. Using Promise.all() when one of the operations might fail, without realizing it rejects immediately as soon as ANY promise rejects, potentially losing the results of the others that already succeeded.
  3. Confusing Promise.all() (fails fast on any rejection) with Promise.allSettled() (waits for everything, reporting both successes and failures).
Chapter Summary
  • Promise.all(arrayOfPromises) runs multiple promises in parallel, resolving once ALL of them succeed, or rejecting as soon as ANY of them fails.
  • Promise.allSettled(arrayOfPromises) also runs in parallel, but always waits for every promise to finish, reporting each one's individual success or failure.
  • Promise.race() resolves or rejects as soon as the FIRST promise in the array settles, whichever that is.
Browser Support

Promise.all() has been supported since Promises were introduced; Promise.allSettled() and Promise.any() are supported in all current major browsers.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.