2

I am fairly new to the concept of promises, I am trying to build a simple pokemon list (aka pokedex). I am using the following code.

I want the names of the pokemons to be listed according to their indicies, I don't want the order to get disturbed. The code that I am using currently using doesn't guarantee this feature.

Inside the forEach() method the fetch() calls are not chained in any manner, so it depends on which response is received first, but I want the then() of index x to be executed before then() of index x+1.

const container = document.querySelector(".container");

fetch('https://pokeapi.co/api/v2/pokemon?limit=150')
  .then(response => response.json())
  .then(json => {
    json.results.forEach((el, index) => {
      fetch(el.url)
        .then(response => response.json())
        .then(json => {
          const pokemonName = el.name;
          const pokemontype = json.types[0].type.name;
          container.innerHTML += `(${index+1}) ${pokemonName} - ${pokemontype} <br>`;
        })
    })
  })
<div class="container"></div>

UPDATE: Below is my solution for the same using Promise.all()

const container = document.querySelector(".container");

fetch('https://pokeapi.co/api/v2/pokemon?limit=150')
  .then(response => response.json())
  .then(json => {
    const responseArr = [];
    json.results.forEach(el => {
      responseArr.push(fetch(el.url));
    });

    return Promise.all(responseArr);
  })
  .then(responses => {
    const jsonArr = [];
    responses.forEach(el => {
      jsonArr.push(el.json());
    });

    return Promise.all(jsonArr);
  })
  .then(jsons => {
    jsons.forEach((json, index) => {
      const pokemonName = json.name;
      const pokemonType = json.types[0].type.name;
      container.innerHTML += `(${index+1}) ${pokemonName} - ${pokemonType} <br>`;
    });
  })
<div class="container"></div>

1 Answers1

1

You can use Promise.all and pass the result from the first API call, this will return the responses in the order as requested:

const container = document.querySelector(".container");

fetch('https://pokeapi.co/api/v2/pokemon?limit=150')
  .then(response => response.json(), e => {
    console.error(e);
    throw e;
  })
  .then(json => {
    Promise.all(json.results.map(el => fetch(el.url)))
      .then(arr => {
        arr.map(response => response.json())
          .forEach((result, index) => {
            result.then(el => {
              const pokemonName = el.name;
              const pokemontype = el.types[0].type.name;
              container.innerHTML += `(${index+1}) ${pokemonName} - ${pokemontype} <br>`;
            })
          })
      }).catch(e => {
        console.error(e)
        throw e;
      });
  }).catch(e => {
    console.error(e)
    throw e;
  });
<div class="container"></div>
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
  • I think your solution is NOT completely correct, because you're using Promise.all() only ONCE. You've assumed that response.json() will follow the order and json promises will be returned in order. Please have a look at my updated question I have pasted my solution there. There I have used Promise.all() twice. Am I doing it incorrectly? –  Aug 13 '20 at 08:13
  • `arr.map(response => response.json()).forEach((result, index) => {result.then(.........` Here result.then() may not follow the order, the first once to get fulfilled will be printed first. –  Aug 13 '20 at 08:17
  • Your Code doesn't work try changing the api endpoint to `https://pokeapi.co/api/v2/pokemon?limit=15` and see how the order gets messed up. –  Aug 16 '20 at 16:30