I'm struggling at the moment as the title would suggest with what I am trying to do. I have some sort of an idea what is happening, although I just can't get it to work 100% how I want to.
After all my promises has been solved I would like to return an Array with all the response data. However for some reason when I return pokemons outside the promise all I get is an empty array. However inside the promise as you see I get after the 5th time, the array I want with 5 objects. The interesting part is in my main function Pokegame, I also console log teamOne. I however get an empty array ("[]") but the the same properties as the console log "inside", however I cant access the keys in this one. I've tried different things but for some reason I just can't return a "normal" array from the function getPokemons.
import React from "react";
import Pokedex from "./Pokedex";
import Pokecard from "./Pokecard";
var PokeAPI = "https://pokeapi.co/api/v2/pokemon/";
const getPokemonIDs = () => {
var team = [];
while (team.length < 5) {
var randomPokemonID = Math.ceil(Math.random() * 807);
team.push(randomPokemonID);
}
return team;
};
const getPokemons = () => {
var pokemonIDs = getPokemonIDs();
var pokemons = [];
Promise.all(pokemonIDs).then(pokemonIDs => {
for (let x in pokemonIDs) {
fetch(PokeAPI + pokemonIDs[x])
.then(response => response.json())
.then(response => {
pokemons.push(response);
console.log("===inside===");
console.log(pokemons);
})
.catch(error => {
console.log(error);
});
}
});
console.log("==end==");
console.log(pokemons.length);
return pokemons;
};
const Pokegame = () => {
const teamOne = getPokemons();
console.log("==teamOne===")
console.log(teamOne);
return (
<div>
<Pokedex team={teamOne} />
</div>
);
};
export default Pokegame;
===inside===
index.js:27 (5) [{…}, {…}, {…}, {…}, {…}]
index.js:27 ==end==
index.js:27 0
===teamOne===
index.js:27 []
0: {abilities: Array(2), base_experience: 63, forms: Array(1), game_indices: Array(0), height: 3, …}
1: {abilities: Array(1), base_experience: 72, forms: Array(1), game_indices: Array(20), height: 6, …}
2: {abilities: Array(3), base_experience: 175, forms: Array(1), game_indices: Array(9), height: 13, …}
3: {abilities: Array(3), base_experience: 81, forms: Array(1), game_indices: Array(17), height: 5, …}
4: {abilities: Array(2), base_experience: 238, forms: Array(1), game_indices: Array(4), height: 16, …}
length: 5
__proto__: Array(0)
index.js:27 ===inside===
index.js:27 [{…}]
index.js:27 ===inside===
index.js:27 (2) [{…}, {…}]
index.js:27 ===inside===
index.js:27 (3) [{…}, {…}, {…}]
index.js:27 ===inside===
index.js:27 (4) [{…}, {…}, {…}, {…}]
index.js:27 ===inside===
index.js:27 (5) [{…}, {…}, {…}, {…}, {…}]
0: {abilities: Array(2), base_experience: 63, forms: Array(1), game_indices: Array(0), height: 3, …}
1: {abilities: Array(1), base_experience: 72, forms: Array(1), game_indices: Array(20), height: 6, …}
2: {abilities: Array(3), base_experience: 175, forms: Array(1), game_indices: Array(9), height: 13, …}
3: {abilities: Array(3), base_experience: 81, forms: Array(1), game_indices: Array(17), height: 5, …}
4: {abilities: Array(2), base_experience: 238, forms: Array(1), game_indices: Array(4), height: 16, …}
length: 5
__proto__: Array(0)
So I know that the promise will get put on the callback queue stack and that's why it returns an empty array the first time, however I do not understand why console log teamOne or even console log pokemons would log an empty array with like attributes?
The issue with Promise.all()
is that there are actually not any promises. Promise.all()
accepts an array of promises, while you are passing an array of IDs.
Try this (logging removed):
Promise.all(
pokemonIDs.map(id => {
return fetch(PokeAPI + id)
.then(response => response.json())
.then(result => {
pokemons.push(result);
});
})
).then(() => {
console.log("==end==");
console.log(pokemons.length);
console.log(pokemons);
});
Forked sandbox here: https://codesandbox.io/s/serverless-breeze-bozdm?file=/src/components/Pokegame.js (slightly edited to integrate with React).
Personally, I like to use Promise.all()
to run parallel requests, but for other cases, I prefer async
/ await
as it is very easy to write and read without too much extra thinking. The original example can then be rewritten like this (provided the parent function is async)
await Promise.all(
pokemonIDs.map(id => {
return fetch(PokeAPI + id)
.then(response => response.json())
.then(result => {
pokemons.push(result);
});
})
);
console.log("==end==");
console.log(pokemons.length);
console.log(pokemons);