Promise.all

HassaniHassani
4 min read

Understanding Promise.all() Like a Pro (Without Losing Your Mind)

If you’re diving into JavaScript, you’ve probably stumbled upon promises. Maybe you’ve already been traumatized by a few unhandled promise rejections. Don’t worry—we’ve all been there. Today, we’ll talk about a promise-related superhero: Promise.all().

Promise.all is like a group project where everyone gets their part done at the same time (no free riders allowed!). But here’s the twist: if one person messes up, the whole project fails. So let’s explore this with two examples, one using the await method and another with .then() chaining.

What Does Promise.all Do?

Promise.all takes an array of promises and runs them concurrently. It waits until all promises resolve or rejects if any one of them fails.

It’s perfect for situations where you want multiple asynchronous tasks to finish before moving forward, like:

  • Fetching data for multiple countries.

  • Loading images for your meme website.

  • Ordering multiple pizzas at once (no waiting for that pineapple pizza 🍍 to arrive first).

NOTE: Promise.all() waits for all promises in the array to either resolve or for one to reject. If any promise rejects, Promise.all() immediately rejects: It short-circuits only when one of the promises rejects.

Example 1: Using Promise.all with async/await

Let’s fetch data for three countries: Japan, Brazil, and Morocco.

const fetchCountries = async function () {
  try {
    const responses = await Promise.all([
      fetch(`https://restcountries.com/v3.1/name/Japan`),
      fetch(`https://restcountries.com/v3.1/name/Brazil`),
      fetch(`https://restcountries.com/v3.1/name/Morocco`),
    ]);

    const data = await Promise.all(responses.map((response) => response.json()));

    console.log(data); // Logs data for Japan, Brazil, and Morocco
  } catch (error) {
    console.error("Uh-oh! Something went wrong:", error.message);
  }
};

fetchCountries();

Breakdown

  1. Promise.all:

    • Sends out three fetch requests at the same time.

    • Returns an array of Response objects when all requests resolve.

    [Response, Response, Response]
  1. .map with response.json():

    • Converts each Response into JSON.

    • This returns another array of promises, which is why we need a second Promise.all to resolve them.

Example 2: Using Promise.all with .then() Chaining

Prefer chaining promises? No problem! Let’s write the same logic without async/await.

Promise.all([
  fetch(`https://restcountries.com/v3.1/name/Japan`),
  fetch(`https://restcountries.com/v3.1/name/Brazil`),
  fetch(`https://restcountries.com/v3.1/name/Morocco`),
])
  .then((responses) => {
    console.log('Responses:', responses); // Logs Response objects
    return Promise.all(responses.map((response) => response.json()));
  })
  .then((data) => {
    console.log('Countries Data:', data); // Logs JSON data
  })
  .catch((error) => {
    console.error('Oops! Error fetching data:', error.message);
  });

Breakdown

  1. First Promise.all:

    • Fetches data concurrently.

    • Returns an array of Response objects if all fetch requests succeed.

  2. .map + Second Promise.all:

    • Processes each Response to JSON.

    • The second Promise.all ensures you get all the parsed data at once.

Why Use a Second Promise.all?

The key here is understanding that response.json() itself returns a Promise. Let’s break this down step by step:

Step 1: What Does fetch Return?

  • fetch gives you a Promise that resolves to a Response object.

  • The Response object has a .json() method, but calling it doesn’t give you data right away. It gives you another Promise!

Step 2: First Promise.all Resolves to Response Objects

When you use Promise.all with multiple fetch calls:

Promise.all([
  fetch(`https://restcountries.com/v3.1/name/Japan`),
  fetch(`https://restcountries.com/v3.1/name/Brazil`),
  fetch(`https://restcountries.com/v3.1/name/Morocco`),
])

This resolves to an array of Response objects:

[Response, Response, Response]

Step 3: .json() Creates More Promises

When you do this:

responses.map((response) => response.json());

You get an array of Promises for JSON data:

[Promise, Promise, Promise]

Step 4: Enter the Second Promise.all

You need to wait for all these JSON Promises to resolve. That’s why you use a second Promise.all:

Promise.all(responses.map((response) => response.json()));

What Happens Without the Second Promise.all?

If you skip the second Promise.all:

responses.map((response) => response.json());

You’ll end up with an array of Promises that haven’t resolved yet. Trying to access data here would be like biting into an unripe fruit—not ready yet! 🍏

Key Takeaways

  1. Promise.all is your friend when working with multiple asynchronous tasks.

  2. You might need a second Promise.all when dealing with promises within promises, like response.json().

  3. Always handle errors with .catch or try...catch. You don’t want your app crashing because of one bad fetch.

Fun Fact

JavaScript doesn’t do anything half-heartedly. If you hand it a promise, it makes sure to follow through—just like how your dog will never leave a ball unchewed. 🐶

Now go forth and conquer those promises like the JavaScript wizard you are! 🧙‍♂️✨

1
Subscribe to my newsletter

Read articles from Hassani directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Hassani
Hassani

Hi 👋 I'm a developer with experience in building websites with beautiful designs and user friendly interfaces. I'm experienced in front-end development using languages such as Html5, Css3, TailwindCss, Javascript, Typescript, react.js & redux and NextJs 🚀