mqbaka mqbaka
mqbaka mqbaka

Reputation: 283

How to count the number of promises that have failed?

I'm working on a small Javascript application that uses an API from pokeapi.co. Basically, it is supposed to fetch a few datas from the API and then display them on an HTML page. Here is the main part of the code :

const searchInput= document.querySelector(".recherche-poke input");
let allPokemon= [];
let tableauFin= [];
const listePoke= document.querySelector('.liste-poke');

function fetchPokemonBase(){
    fetch("https://pokeapi.co/api/v2/pokemon?limit=75")
        .then(reponse => reponse.json())
        .then((allPoke) =>{
            allPoke.results.forEach((pokemon) =>{
                fetchPokemonComplet(pokemon);
            })
        })
}

fetchPokemonBase();

function fetchPokemonComplet(pokemon){
    let objPokemonFull = {};
    let url = pokemon.url;
    let nameP = pokemon.name;

    fetch(url)
        .then(reponse => reponse.json())
        .then((pokeData) => {
            objPokemonFull.pic = pokeData.sprites.front_default;
            objPokemonFull.type = pokeData.types[0].type.name;
            objPokemonFull.id = pokeData.id;

            fetch(`https://pokeapi.co/api/v2/pokemon-species/${nameP}`)
                .then(reponse => reponse.json())
                .then((pokeData) => {
                    objPokemonFull.name= pokeData.names[4].name;
                    allPokemon.push(objPokemonFull);

                    if(allPokemon.length === 75){
                        tableauFin= allPokemon.sort((a, b) => {
                            return a.id - b.id;
                        }).slice(0, 21);

                        createCard(tableauFin);
                    }
                })
        });
}

function createCard(arr){
    for(let i= 0; i< arr.length; i++){
        console.log(i + '\n');

        const carte= document.createElement("li");
        const txtCarte= document.createElement('h5');
        txtCarte.innerText= arr[i].name;
        const idCarte= document.createElement('p');
        idCarte.innerText= `ID# ${arr[i].id}`;
        const imgCarte= document.createElement('img');
        imgCarte.src= arr[i].pic;

        carte.appendChild(imgCarte);
        carte.appendChild(txtCarte);
        carte.appendChild(idCarte);

        listePoke.appendChild(carte);
    }
}

Here's what the code does : it gather a list of 75 pokemons from the pokeapi API. Then it fetches the data about each pokemon from the same site and stores each data into one element of the allPokemon array, when the length of this array reaches 75, we begin to create the HTML elements to display the data.

The ambigious part here is :

if(allPokemon.length === 75){
    tableauFin= allPokemon.sort((a, b) => {
        return a.id - b.id;
        }).slice(0, 21);
    
   createCard(tableauFin);
  }

This code works but only when none of the requests fail. Otherwise, the length of the array allPokemon never reaches 75 and the rest of the code won't be executed. When I run the code, I run on XHR GET errors and the script stops before displaying the datas and it's (I think) what caused one of the promises to fail. I tried things like if(allPokemon.length === 74) (if I have one error, for example) and the code works just fine but that is surely not the solution.

Is there a way for me to "count" the errors I get from my requests so that I can do something like if(allPokemon.length === 75 - errorsCount) or maybe there is a smarter way to write my code?

Thanks in advance.

Upvotes: 1

Views: 362

Answers (2)

Trystian Offerman
Trystian Offerman

Reputation: 26

I think you can use promise all for this. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

function fetchPokemonBase(){
    const promises = []

    fetch("https://pokeapi.co/api/v2/pokemon?limit=75")
        .then(reponse => reponse.json())
        .then((allPoke) =>{
            allPoke.results.forEach((pokemon) =>{
                promises.push(fetchPokemonComplet(pokemon).catch(error => console.error(error)));
            })
        })
        .then(() => {
          Promise.all(promises)
            .then(() => {
              tableauFin= allPokemon.sort((a, b) => {
                return a.id - b.id;
              }).slice(0, 21);

              createCard(tableauFin);
            })
        })
}

fetchPokemonBase();
let counter = 0
function fetchPokemonComplet(pokemon){
    let objPokemonFull = {};
    let url = pokemon.url;
    let nameP = pokemon.name;
    return fetch(url)
    .then(reponse => reponse.json())
    .then((pokeData) => {
            counter++;
            objPokemonFull.pic = pokeData.sprites.front_default;
            objPokemonFull.type = pokeData.types[0].type.name;
            objPokemonFull.id = pokeData.id;
            return fetch(`https://pokeapi.co/api/v2/pokemon-species/${nameP}`)
                .then(reponse => reponse.json())
                .then((pokeData) => {
                    objPokemonFull.name= pokeData.names[4].name;
                    allPokemon.push(objPokemonFull);

                })
        });
}

So what you do is, instead of executing the fetch in the foreach, we push each fetch to an array of promises. Then we use the promise.all to execute them, and for each promise we catch the errors. So if one fails, the next promise will just continue.

With this code we push every fetch for the individual pokemons to an array:

promises.push(fetchPokemonComplet(pokemon).catch(error => console.error(error)));

Then we have an array of promises, which are the fetches to the server. With the following code we execute these promises.

Promise.all(promises)
                .then(() => {
                  tableauFin= allPokemon.sort((a, b) => {
                    return a.id - b.id;
                  }).slice(0, 21);
    
                  createCard(tableauFin);
                })

the then on promise.all will be executed when all the promises are done. And since we catch on every individual promise we don't have to worry about that. And we don't care about the length and don't have to keep count. Let me know if it works, or need any help.

Upvotes: 1

From what I see, you will receive a list of between 0 and 75 pokemons from the first API call. Then, you fetch each one, however many it returned, up to 75 entries.

So, I think you want to just make sure your list isn't empty: if(allPokemon.length > 0)

Upvotes: 0

Related Questions