Search code examples
javascriptecmascript-6es6-promise

How to resolve “Value below was evaluated just now.” for chained then functions


I am using https://pokeapi.co/ API to fetch all pokemon. I am trying to iterate through each pokemon list https://pokeapi.co/api/v2/pokemon/?limit=44 and get the data. I am using promise for this. But my promise is returning me“Value below was evaluated just now”.

I have already tried workaround for this:-

1. JSON.stringify().
2. JSON.parse(JSON.stringify())
3. setTimeout
4. map, concat etc.

var getPokemonList = new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "https://pokeapi.co/api/v2/pokemon/?limit=4");
    xhr.onload = () => resolve(JSON.parse(xhr.responseText));
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
});

var getPokemonListDetails = getPokemonList
    .then(function (fulfilledList) {
        console.log(fulfilledList.results);
        var pokemonList = [];
        setTimeout(() => {
            fulfilledList.results.forEach(function (pokemon) {
                const xhr = new XMLHttpRequest();
                xhr.open("GET", pokemon.url);
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        pokemonList.push(JSON.parse(xhr.responseText));
                    }
                };
                xhr.send();
            });
        }, 3000); 
        return pokemonList;
    })
    .then(function (fulfilledListDetails) {
        console.log(fulfilledListDetails);
    })
    .catch(function (error) {
        console.log(error.message);
    });

The above code giving me “Value below was evaluated just now” array data. What I can do to make it usable.


Solution

  • You correctly used a Pomise to wrap the first API call, however you did not wrap the timer and the other API calls, therefore the promise resolves before they are done. Modern browsers support fetch() which is way easier to use than XMLHttpRequest, and it already returns a Promise which can easily be chained. Now the only thing thats left is to wrap the timeout:

     const delay = ms => new Promise(res => setTimeout(res, ms));
    

    Now that we have all these Promises, Promise.all and chaining can be used to combine them:

     const pokemonList = fetch(  "https://pokeapi.co/api/v2/pokemon/?limit=4" ).then(res => res.json());
    
     const pokemonDetails = pokemonList.then(list => {
       return delay(3000).then(() => {
         return Promise.all(list.results.map(pokemon => {
           return fetch(pokemon.url).then(res => res.json());
        });
      });
     });