← Back

HANDLING MULTIPLE PROMISES IN JAVASCRIPT

Sometimes you need to work with many promises at the same time.

This note explains how to handle multiple promises in simple language.

You will learn:

  1. why group promise methods are needed
  2. how Promise.all() works
  3. how Promise.allSettled() works
  4. how Promise.race() works
  5. when to use each one
  6. common beginner mistakes

1. Why do we need methods for multiple promises?

Sometimes one promise is not enough.

For example, you may need to:

All at the same time.

Or maybe you only care about the fastest result.

JavaScript has special methods for this.

Diagram 1. One promise vs many promises

One async task
-> one promise

Many async tasks
-> many promises
-> need a way to manage them together

This is why methods like Promise.all(), Promise.allSettled(), and Promise.race() exist.

2. Promise.all()

Promise.all() is used when you want to wait for all promises to succeed.

Syntax

Promise.all([promise1, promise2, promise3])

It takes an array of promises and returns one new promise.

Diagram 2. Main idea of Promise.all()

Promise.all([...])
-> wait for all promises

if all succeed
-> one fulfilled promise with array of results

if one fails
-> one rejected promise with that error

3. Example: all promises succeed

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);

Promise.all([p1, p2, p3])
  .then(values => console.log(values))
  .catch(error => console.log(error));

Output

[1, 2, 3]

All 3 promises were fulfilled.

So Promise.all() also becomes fulfilled.

Its result is an array of values.

Diagram 3. Promise.all() success flow

p1 -> fulfilled -> 1
p2 -> fulfilled -> 2
p3 -> fulfilled -> 3
-> Promise.all(...)
-> fulfilled with [1, 2, 3]

4. Important rule: result order

The result array keeps the same order as the promises in the input array.

It does not depend on which promise finishes first.

Example idea

Input order:
[p1, p2, p3]

Result order:
[value of p1, value of p2, value of p3]

Diagram 4. Order rule

Input:
[p1, p2, p3]

Even if p3 finishes first,
the result still stays:

[result of p1, result of p2, result of p3]

This is very important. Promise.all() preserves input order.

5. Example: one promise fails

const p1 = Promise.resolve(1);
const p2 = Promise.reject("Rejected promise 2");
const p3 = Promise.resolve(3);

Promise.all([p1, p2, p3])
  .then(values => console.log(values))
  .catch(error => console.log(error));

Output

"Rejected promise 2"

As soon as one promise is rejected, Promise.all() becomes rejected too.

So then() does not run. catch() runs instead.

Diagram 5. Promise.all() failure flow

p1 -> fulfilled
p2 -> rejected
p3 -> fulfilled
-> Promise.all(...)
-> rejected with error from p2

6. Does Promise.all() wait after a rejection?

Easy answer: Promise.all() does not wait for a final success result after one rejection.

It rejects as soon as the first rejection happens.

But also important: the other promises may still continue running in the background, because JavaScript usually cannot magically stop them.

Promise.all() settles early,
but other original promises may still continue.

Diagram 6. Rejection in Promise.all()

p1 still running
p2 rejects
p3 still running
-> Promise.all(...) rejects immediately
-> result is already decided

Clean beginner rule:

Promise.all() = all must succeed
one rejection = whole result fails

7. When to use Promise.all()

Use Promise.all() when:

Example uses:

Diagram 7. When to use Promise.all()

Need all results?
-> Yes
-> Use Promise.all()

8. Promise.allSettled()

Promise.allSettled() is used when you want to wait for all promises to finish, no matter whether they succeed or fail.

Syntax

Promise.allSettled([promise1, promise2, promise3])

It also returns one promise.

But unlike Promise.all(), this returned promise always fulfills.

Diagram 8. Main idea of Promise.allSettled()

Promise.allSettled([...])
-> wait for all promises to finish
-> always fulfilled
-> returns array with status of each promise

9. Example of Promise.allSettled()

const p1 = Promise.resolve(1);
const p2 = Promise.reject("Rejected promise 2");
const p3 = Promise.resolve(3);

Promise.allSettled([p1, p2, p3])
  .then(results => console.log(results));

Output

[
  { status: "fulfilled", value: 1 },
  { status: "rejected", reason: "Rejected promise 2" },
  { status: "fulfilled", value: 3 }
]

This method waits for all promises.

It does not fail just because one promise failed. Instead, it gives an array of result objects.

Very important correction

For rejected promises, the property is reason, not value.

Diagram 9. allSettled() result objects

Fulfilled promise
-> { status: "fulfilled", value: result }

Rejected promise
-> { status: "rejected", reason: error }

This is one of the most common beginner mistakes.

10. Why catch() is usually not needed for allSettled()

Because the promise returned by Promise.allSettled() itself does not reject in the normal use case.

It always gives you the final array.

So usually you just use:

.then(...)

Diagram 10. allSettled() behavior

Some promises succeed
Some promises fail
-> Promise.allSettled(...)
-> still fulfilled

11. When to use Promise.allSettled()

Use it when:

Example uses:

Diagram 11. When to use Promise.allSettled()

Need result of every promise?
Need success and failure info?
-> Use Promise.allSettled()

12. Promise.race()

Promise.race() is used when you only care about the first settled promise.

Settled means:

Syntax

Promise.race([promise1, promise2, promise3])

It returns one promise. That returned promise settles as soon as the first input promise settles.

Diagram 12. Main idea of Promise.race()

Promise.race([...])
-> watch all promises
-> first settled one wins
-> all others are ignored for the final result

13. Example: first fulfilled promise wins

const p1 = new Promise(resolve => {
  setTimeout(() => resolve(1), 1000);
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => reject(2), 2000);
});

Promise.race([p1, p2])
  .then(value => console.log(value))
  .catch(error => console.log(error));

Output

1

p1 finished first after 1 second. It was fulfilled.

So Promise.race() also became fulfilled with value 1.

Diagram 13. Race with success first

p1 -> fulfilled after 1 second
p2 -> rejected after 2 seconds
-> Promise.race(...)
-> fulfilled with 1

14. Example: first rejected promise wins

const p1 = new Promise(resolve => {
  setTimeout(() => resolve(1), 2000);
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => reject(2), 1000);
});

Promise.race([p1, p2])
  .then(value => console.log(value))
  .catch(error => console.log(error));

Output

2

p2 finished first after 1 second. It was rejected.

So Promise.race() also became rejected with 2.

Diagram 14. Race with rejection first

p1 -> fulfilled after 2 seconds
p2 -> rejected after 1 second
-> Promise.race(...)
-> rejected with 2

15. Does Promise.race() wait for the others?

No.

As soon as one promise settles, the result of Promise.race() is already decided.

The other promises may still continue in the background, but they do not matter anymore for the returned promise.

Diagram 15. Promise.race() stops caring

first promise settles
-> Promise.race(...) settles
-> other promises no longer affect the result

16. Promise.all() vs Promise.allSettled() vs Promise.race()

This is the most important comparison.

Promise.all()

Promise.allSettled()

Promise.race()

Diagram 16. Full comparison

Promise.all()
-> all must succeed

Promise.allSettled()
-> all must finish

Promise.race()
-> first settled wins

17. Which one should I choose?

Use this simple rule:

Diagram 17. Choice guide

Need all results, and all must succeed?
-> Promise.all()

Need all results, even failed ones?
-> Promise.allSettled()

Need only the fastest result?
-> Promise.race()

18. Common beginner mistakes

Mistake 1. Thinking Promise.all() returns an array

It does not return an array directly. It returns a promise. That promise may later fulfill with an array.

Mistake 2. Thinking Promise.allSettled() can reject because one promise failed

It does not reject for that reason. It still fulfills with status objects.

Mistake 3. Using value for rejected results in allSettled()

Wrong:

{ status: "rejected", value: error }

Correct:

{ status: "rejected", reason: error }

Mistake 4. Thinking Promise.race() waits for all promises

It does not. It finishes when the first promise settles.

Mistake 5. Thinking Promise.all() result order depends on finish speed

It does not. The result order matches the input array order.

Diagram 18. Common mistakes summary

Promise.all() -> returns promise, not array
allSettled() -> rejected results use reason
race() -> first settled only
all() result order -> input order

19. Easy memory rules

Promise.all()
= all together, all must succeed

Promise.allSettled()
= all together, show every final result

Promise.race()
= fastest one wins

20. Quick summary

21. Final conclusion

If you understand these ideas:

Promise.all()
Promise.allSettled()
Promise.race()
all must succeed
all must finish
fastest promise wins

then you already have a strong foundation for handling multiple promises in JavaScript.

These methods are very important in real projects because applications often run many asynchronous tasks at the same time.

← Back