5

I'm getting an object coming from an API and I'm creating new objects inside it with other API responses, ex:

API Response 1: Obj: {a: 1, b: 2}

API Response 2: 3

Creating an object: Obj.c = 3

Final result: Obj: {a: 1, b: 2, c: 3}

Problem:

console.log(Obj) return Obj: {a: 1, b: 2, c: 3}

console.log(Obj.c) return undefined

I am not getting when trying to give a console.log after the .map in the properties, I can not access the created properties, returns undefined. However, when I give a console.log on any object, the created properties are there.

My Code:

async getGeneralInfo(token, seed) {
    try {
        API_HEADER.headers.Authorization = token;
        let responseAvaliableCoins = await axios.get(
            BASE_URL + "/coin",
            API_HEADER
        );

        let avaliableCoins = responseAvaliableCoins.data.data.coins;

        avaliableCoins.map(async (coin, index) => {
            if (coin.status === "active") {
                let responseCreateAddress = await axios.post(
                    BASE_URL + "/coin/" + coin.abbreviation + "/address",
                    { seed },
                    API_HEADER
                );

                avaliableCoins[index].address =
                    responseCreateAddress.data.data.address;

                let responseBalance = await axios.get(
                    BASE_URL +
                    "/coin/" +
                    coin.abbreviation +
                    "/balance/" +
                    coin.address,
                    API_HEADER
                );

                avaliableCoins.token = responseBalance.headers[HEADER_RESPONSE];
                avaliableCoins[index].balance = responseBalance.data.data;
            } else {
                avaliableCoins[index].address = undefined;
                avaliableCoins[index].balance = undefined;
            }
        });

        console.warn(avaliableCoins[0].balance); //undefined
        console.warn(avaliableCoins[0]["balance"]); //undefined
        console.warn(avaliableCoins[0].address); //undefined
        console.warn(avaliableCoins[0]["address"]); //undefined

        console.warn("avaliableCoins", avaliableCoins); //All objects are here
        console.warn("avaliableCoins[0]", avaliableCoins[0]); //All objects are here

        return avaliableCoins;
    } catch (error) {
        internalServerError();
        return;
    }
}

update ----- enter image description here

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
Guers4
  • 75
  • 1
  • 1
  • 6
  • Did you check to ensure that the 0 index has something. I might just dump the entire availableCoins array to see what you're working with. console.log(avaliableCoins) – bob Aug 12 '18 at 02:27
  • 1
    My theory is that you're using Google Chrome, which shows a "live" view when you log objects. Your code isn't `await`ing the result of all the promises returned from the `.map`. – 4castle Aug 12 '18 at 02:32
  • `const coinUpdates = availableCoins.map( ... etc ... ); await Promise.all(coinUpdates);` – 4castle Aug 12 '18 at 02:41
  • 1
    That `i` next to the object says it was evaluated just now. So possibly its not the same value at the time you wrote to the console. – Nimeshka Srimal Aug 12 '18 at 02:45

1 Answers1

4

The function used in map is asynchronous.

Right now map is being called on all of the coins and before all the asynchronous data can come back the code has already moved on to the console.warn() calls.

availableCoins will eventually be updated with all the asynchronous data as it is returned, but there is a race condition here since the code is not explicitly waiting for that to happen.

Here is the recommended approach:

  • return a modified item from each async call in map, this will return a Promise that will resolve to the modified item when the async function completes.
  • use Promise.all() to wait on the array of Promises
  • return the resulting array

Here is a simplified version that demonostrates the approach:

const getData = () => {
  return Promise.resolve('data');
}

export const getGeneralInfo = async () => {
  let avaliableCoins = [
    { a: 1 },
    { a: 2 }
  ]

  const promises = avaliableCoins.map(async (coin) => {
    let response = await getData();
    // modify coin and return it
    coin.data = response;
    return coin;
  });

  const updatedCoins = await Promise.all(promises);

  console.log(updatedCoins); // [{a: 1, data: 'data'}, {a: 2, data: 'data'}]

  return updatedCoins;
}

Your modified function would look like this:

async getGeneralInfo(token, seed) {
  try {
    API_HEADER.headers.Authorization = token;
    let responseAvaliableCoins = await axios.get(
      BASE_URL + "/coin",
      API_HEADER
    );

    let avaliableCoins = responseAvaliableCoins.data.data.coins;

    const promises = avaliableCoins.map(async (coin) => {
      if (coin.status === "active") {
        let responseCreateAddress = await axios.post(
          BASE_URL + "/coin/" + coin.abbreviation + "/address",
          { seed },
          API_HEADER
        );

        coin.address =
          responseCreateAddress.data.data.address;

        let responseBalance = await axios.get(
          BASE_URL +
          "/coin/" +
          coin.abbreviation +
          "/balance/" +
          coin.address,
          API_HEADER
        );

        coin.token = responseBalance.headers[HEADER_RESPONSE];
        coin.balance = responseBalance.data.data;
      } else {
        coin.address = undefined;
        coin.balance = undefined;
      }
      return coin;
    });

    availableCoins = await Promise.all(promises);

    console.warn(avaliableCoins[0].balance); //undefined
    console.warn(avaliableCoins[0]["balance"]); //undefined
    console.warn(avaliableCoins[0].address); //undefined
    console.warn(avaliableCoins[0]["address"]); //undefined

    console.warn("avaliableCoins", avaliableCoins); //All objects are here
    console.warn("avaliableCoins[0]", avaliableCoins[0]); //All objects are here

    return avaliableCoins;
  } catch (error) {
    internalServerError();
    return;
  }
}
Brian Adams
  • 43,011
  • 9
  • 113
  • 111