These are the functions that I have created
the function prova does the fetch in the for cycle then create the various variables with the value of the things that I want to display
function prova() {
//Ciclo la fetch per avere solamente i pokemon di settima generazione
for (let index = 1; index < 899; index ) {
const id = index;
fetch(
`https://pokeapi.co/api/v2/pokemon/${id}/`,
{ method: "GET" }
//Attendo la risposta del server
).then(async (response) => {
//do il valore dei vari oggetti alle variabili
let rispostaFetch = await response.json();
let pokemonNumber = rispostaFetch.id;
let pokemonName = rispostaFetch.name.charAt(0).toUpperCase() rispostaFetch.name.slice(1); //Rendo maiuscola solo la prima lettera
//Do il valore a pokemontypes di un nuovo array contente gli elementi dell'array pokemontypes.type.name con il metodo .map()
let pokemontypes=rispostaFetch.types.map((pokemontypes) => pokemontypes.type.name)
let pokemontype1 = pokemontypes[0];
let pokemontype2 =pokemontypes[1];
Card(pokemontype1,pokemontype2,pokemonNumber,pokemonName);
});
}
}
The Card function creates the divs and then the appendchild to the pokGen divs
function Card(pokemontype1,pokemontype2,pokemonNumber,pokemonName) {
//creo dinamicamente un Div con classe .pokemonCard il risultato della funzione ActiveTypeSecond che dinamicamente mette il tipo di carta (fuoco, erba)
// e metto come id #pokemon# la variabile pokemonNumber (il risultato sarà: #pokemon#1 ecc)
let pokemonWrapper = document.createElement('div');
pokemonWrapper.classList.add("pokemonCard", ActiveTypeSecond(pokemontype1.toLowerCase()));
pokemonWrapper.id ='pokemon#' pokemonNumber;
//All'interno di questo div avrà quanto segue:
pokemonWrapper.innerHTML = `
<div class="pokemonPicture">
<img class="pokemonImage" src="https://assets.pokemon.com/assets/cms2/img/pokedex/full/${ActiveLink(pokemonNumber)}.png" alt="">
</div>
<div class="pokemonName&Number">
<span class ="numeroPokemon">N°${pokemonNumber}</span>
<h3 class ="nomePokemon">${pokemonName}</h3>
</div>
<div class="pokemonTipo">
<ul class="pokemonlista">
<li class="pokemonType">Type:</li>
<span class="separatore"></span>
${Type2Pokemon(pokemontype1,pokemontype2,)}
</ul>
</div>`;
if (pokemonNumber <152) {
const pokGen1 = document.getElementById('PrimaGen')
pokGen1.appendChild(pokemonWrapper)
pagina.appendChild(pokGen1)
}
if (pokemonNumber > 151 && pokemonNumber < 252) {
const pokGen2 = document.getElementById('SecondaGen')
pokGen2.appendChild(pokemonWrapper)
pagina.appendChild(pokGen2)
}
if (pokemonNumber > 251 && pokemonNumber < 387) {
const pokGen3 = document.getElementById('TerzaGen')
pokGen3.appendChild(pokemonWrapper)
pagina.appendChild(pokGen3)
}
if (pokemonNumber > 386 && pokemonNumber < 494) {
const pokGen4 = document.getElementById('QuartaGen')
pokGen4.appendChild(pokemonWrapper)
pagina.appendChild(pokGen4)
}
if (pokemonNumber > 493 && pokemonNumber < 650) {
const pokGen5 = document.getElementById('QuintaGen')
pokGen5.appendChild(pokemonWrapper)
pagina.appendChild(pokGen5)
}
if (pokemonNumber > 649 && pokemonNumber < 722) {
const pokGen6 = document.getElementById('SestaGen')
pokGen6.appendChild(pokemonWrapper)
pagina.appendChild(pokGen6)
}
if (pokemonNumber > 722 && pokemonNumber < 810) {
const pokGen7 = document.getElementById('SettimaGen')
pokGen7.appendChild(pokemonWrapper)
pagina.appendChild(pokGen7)
}
if (pokemonNumber > 809 && pokemonNumber < 899) {
const pokGen8 = document.getElementById('OttavaGen')
pokGen8.appendChild(pokemonWrapper)
pagina.appendChild(pokGen8)
}
}
after the various appendchild the order of the divs is wrong, how can I fix it?
CodePudding user response:
Welcome to the asyncronous world!
You send 898 calls at the same time, but the code inside then(async (response) => { }
is evaluated each time a call gets its response from the server.
However, you have no control over which call arrives first. If you want them to be already in order, you need to wait for the first call to complete, before starting the other.
Otherwise, when you get each response you insert the pokemon at the right place.
A better endpoint
In case you need many resources (let's say more than 10) it's usually not a good practice to send a single request for each resource. If you are in control of the backend, you better make an endpoint giving multiple results.
As far as I can see, pokeapi has the Generations endpoint.
You might want to use that :)
(for example https://pokeapi.co/api/v2/generation/1
)
CodePudding user response:
fetch
calls your callback function (.then(async (response) => {...}
) to return the data asynchronously. This results in your requests (898 to be exact) not to resolve in the order your requested but when the data got sent to you and is ready.
I highly recommend you check out https://javascript.info/promise-basics (or a different tutorial on promises) to understand how asynchronous execution and promises work in JavaScript.
How to fix this for your code:
- Await each request before requesting another.
async function prova() {
for (let index = 1; index < 899; index ) {
const id = index;
const response = await fetch(
`https://pokeapi.co/api/v2/pokemon/${id}/`,
{ method: "GET" }
//Attendo la risposta del server
);
//do il valore dei vari oggetti alle variabili
let rispostaFetch = await response.json();
let pokemonNumber = rispostaFetch.id;
let pokemonName = rispostaFetch.name.charAt(0).toUpperCase() rispostaFetch.name.slice(1); //Rendo maiuscola solo la prima lettera
//Do il valore a pokemontypes di un nuovo array contente gli elementi dell'array pokemontypes.type.name con il metodo .map()
let pokemontypes=rispostaFetch.types.map((pokemontypes) => pokemontypes.type.name)
let pokemontype1 = pokemontypes[0];
let pokemontype2 =pokemontypes[1];
Card(pokemontype1,pokemontype2,pokemonNumber,pokemonName);
}
}
- Wait for all requests to be finished and process them then.
async function prova() {
// collect returned promises of fetch
let pendingResponses = [];
for (let index = 1; index < 899; index ) {
const id = index;
const promise = fetch(
`https://pokeapi.co/api/v2/pokemon/${id}/`,
{ method: "GET" }
//Attendo la risposta del server
);
pendingResponses.push(promise);
}
// await them all
const responses = await Promise.all(pendingResponses);
// process the returned list of responses
for (const response of responses) {
//do il valore dei vari oggetti alle variabili
let rispostaFetch = await response.json();
let pokemonNumber = rispostaFetch.id;
let pokemonName = rispostaFetch.name.charAt(0).toUpperCase() rispostaFetch.name.slice(1); //Rendo maiuscola solo la prima lettera
//Do il valore a pokemontypes di un nuovo array contente gli elementi dell'array pokemontypes.type.name con il metodo .map()
let pokemontypes=rispostaFetch.types.map((pokemontypes) => pokemontypes.type.name)
let pokemontype1 = pokemontypes[0];
let pokemontype2 =pokemontypes[1];
Card(pokemontype1,pokemontype2,pokemonNumber,pokemonName);
}
}
- Sort the appended divs after one was added.
(I'm not writing the code for this one)
However...
Making 898 API requests simultaneously isn't a good idea, but waiting for them to load sequentially takes too long either. So in practice an API returning a requested list of Pokémon should be used, or the displayed HTML list should only be extended if the user scrolled down... But for training the current way should be ok enough. ;)