0

I am creating an array of objects from an endpoint with the fetch api. Each object in the response contains a new url and I scan this array for new objects. The purpose is to access the endpoint, obtain the urls and access these urls to store your objects and attributes. But when accessing the array with objects and from an index it returns undefined.

let url = [];
let pokemon = [];
    
function getPokemons(){

    fetch("https://pokeapi.co/api/v2/type/11/")
        .then(async response =>{ 
            await response.json().then(data => 
                data.pokemon.forEach(item => 
                    url.push(item.pokemon.url)
                )
            )
        }).then( response => {

            url.map(item => 
                fetch(item).then(response =>{ 
                    response.json().then(data => 
                        pokemon.push(data)
                    )
                })
            )

        })

}

getPokemons()

console.log(pokemon[1])

2 Answers2

1

The problem is that the function getPokemons should be async. You should await it before accessing:

getPokemons().then(()=> console.log(pokemon[1]))
// or if it inside an async function:
await getPokemons();
console.log(pokemon[1]);

But there's another reason also. You have internal promises outside the parent promise chain. I mean:

.then((response) => {
  // this is array of promises
  // you should return it to have ability await it on parent promise
  url.map((item) =>
    fetch(item).then((response) => {
      response.json().then((data) => pokemon.push(data));
    })
  );
});

Your code might look like:

// if you really need global variable
let pokemon = [];

async function getPokemons() {
  const result = await fetch("https://pokeapi.co/api/v2/type/11/")
    .then((response) => response.json())
    .then((data) =>
      Promise.all(
        data.pokemon.map((item) =>
          fetch(item.pokemon.url).then((response) => response.json())
        )
      )
    );

  pokemon.push(...result);
}

getPokemons().then(() => {
  console.log(pokemon[1]);
});

Or, the same result without global variables:

function getPokemons() {
  return fetch("https://pokeapi.co/api/v2/type/11/")
    .then(...)
    .then(...);
}

getPokemons().then((pokemons) => {
  console.log(pokemons[1]);
});
Ramil Garipov
  • 465
  • 2
  • 7
  • 1
    Ramil explaind very well - you get undefined because fetch is async operation and pokemon[1] is an attempt to get the first element of pending promise. There is nor first neither any other elements yet. – Tarukami Jul 25 '20 at 21:52
  • Thank you for your help. I need to practice a lot – Kewin Costa Jul 25 '20 at 22:58
1

Solution for web browser :

The node-fetch module is not required, I just clean your code using async/await syntax.

// getPokemon is now an async function for cleaner syntax
async function getPokemon() {
    const pokemon = [];

    // Then we can use await
    const response = await fetch("https://pokeapi.co/api/v2/type/11/"),
        json = await response.json(),
        urls = json.pokemon.map(item => item.pokemon.url);

    for (const url of urls) {
        const response = await fetch(url),
            json = await response.json();
        pokemon.push(json)
    }

    // We return the pokemon array instead of polluting global scope
    return pokemon;
};

getPokemon().then(pokemon => {
    console.log(pokemon)
});

Hope it help !

NodeJS solution

You must install node-fetch (see npmjs.org :

npm install -D node-fetch

Then you can use a fetch:

// Importing the node module.
// You can delete this line if your not using a node environment.
const fetch = require('node-fetch');

// getPokemon is now an async function for cleaner syntax
async function getPokemon() {
    const pokemon = [];

    // Then we can use await
    const response = await fetch("https://pokeapi.co/api/v2/type/11/"),
        json = await response.json(),
        urls = json.pokemon.map(item => item.pokemon.url);

    for (const url of urls) {
        const response = await fetch(url),
            json = await response.json();
        pokemon.push(json)
    }

    // We return the pokemon array instead of polluting global scope
    return pokemon;
};

getPokemon().then(pokemon => {
    console.log(pokemon)
});

Explanation

fetch is not part of the Javascript language specification but is a Web API. Each browser may or not choose to implement it. Each Implementations may work differently under the hood but the Javascript API provided must match the standard (MDN Web Docs).

This is why you need a module to fetch the data.

EDIT : Adding solution for web browser environment

negrel
  • 96
  • 5