Async function behaves differently in array push [SOLVED]

I have very basic async function going on here. my primary function "formatData" is formatting some data from an array "arr" . which are basically some github usernames.

This function formats the data in this way :

[
  { name: 'rocktimsaikia', followers: 12 },
  { name: 'aholachek', followers: 90 },
  { name: 'benawad', followers: 30 }
]

Very basic . But the issue is to get the followers count i created another async function "getFollowers" which extracts the followers count with given argument which is the github user name that i am providing in formatData.

Here is my code :

const getFollowers = async name => {
  const data = await fetch(`https://api.github.com/users/${name}`);
  const { followers } = await data.json();
  return followers;
};

const formatData= () => {
  const arr = ["rocktimsaikia", "aholachek", "benawad"];
  const result = [];
  arr.map(async i => {
    result.push({
      name: i,
      followers: await getFollowers(i)
    });
  });
  return result;
};

But the function returns the empty array "result" before the "getFollowers" is resolved.
So basically i want the whole array map loop to resolve before it reaches to return the empty array. What am i missing here ?

  • that’s not how you use map, it’s not just a different syntax for a loop.
  • the format function is synchronous, and what is in it is subject to normal JS rules: arr is declared, result is declared. You declare you’re going to do some async operation. In the meantime, result is returned (and it’s an empty array).

Edit: a few ways to do this, example

const formatData= async () => {
  const users = ["rocktimsaikia", "aholachek", "benawad"];
  const result = await users.map(async (user) => ({
      name: user,
      followers: await getFollowers(user)
   }));
  return result;
};

Promise.all is generally what you want in this case though, code would be similar to above but the requests will happen basically all at once rather than sequentially.

1 Like

That does not seem to work .Plus i have already tried it that way. "await" has no effect in
this type expression

It just returns everything with a promise.

Ah wasn’t tested, just written on phone, need to resolve the map of promises so should be more like this (still not tested, still on phone):

const result = await users.map(async (name) => {
   const followers = await getFollowers(user);
   return { name, followers };
});
// Resolve all promises in the array:
return await Promise.all(result);

Do you understand why your code doesn’t work though? That function has to be asynchronous

@DanCouper, you don’t need that first await though…
@RocktimSaikia, as @DanCouper, pointed out, you need to make an array of promises and:

  1. either pass it like that, then any expecting party would have to const users = await Promise.all(response);
  2. or make your formatData an async and return await Promise.all(result);

You can choose either way (2nd preferably), but the key here is to have array of promises, whereas in your first example promise is nested inside object…

2 Likes

Yeah i already figured it out. Promise.all() solved my issue.Initially i wasn’t sure on how it worked but MDN documented it pretty well.

The Promise.all() method returns a single Promise that resolves when all of the promises passed as an iterable have resolved.

Took a good look and it all made sense. But thanks anyway :slight_smile:

Yeah, I always forget the exact syntax & I didn’t have a chance to check it, sorry for the phone posting