Ognjen Kljajic
Ognjen Kljajic

Reputation: 37

Pushing elements into the array works only inside the loop

I got some data which I'm calling from API and I am using axios for that. When data is retrieved, I dump it inside of a function called "RefractorData()" just to organize it a bit, then I push it onto existing array. The problems is, my array gets populated inside forEach and I can console.log my data there, but once I exit the loop, my array is empty.

let matches: any = new Array();
const player = new Player();

    data.forEach(
          async (match: any) => {
            try {
              const result = await API.httpRequest(
                `https://APILink.com/matches/${match.id}`,
                false
              );
              if (!result) console.log("No match info");
              const refractored = player.RefractorMatch(result.data);
              matches.push({ match: refractored });
              console.log(matches);
            } catch (err) {
              throw err;
            }
          }
        );
        console.log(matches);

Now the first console.log inside forEach is displaying data properly, second one after forEach shows empty array.

Upvotes: 0

Views: 71

Answers (2)

Ognjen Kljajic
Ognjen Kljajic

Reputation: 37

Managed to do it with Promise.all() and Array.prototype.map() .

const player = new Player();
const matches = result.data;

const promises = matches.map(async (match: any) => {
  const response: any = await API.httpRequest(
    `https://API/matches/${match.id}`,
    false
  );

  let data = response.data;
  return {
    data: player.RefractorMatch(data)
  };
});
const response: any = await Promise.all(promises);

Upvotes: 1

Elias Soares
Elias Soares

Reputation: 10254

You must understand that async functions almost always run later, because they deppend on some external input like a http response, so, the second console.log is running before the first.

There a few ways to solve this. The ugliest but easiest to figure out is to create a external promise that you will resolve once all http requests are done.

let matches = [];
let promise = new Promise((resolve) => {
    let complete = 0;
    data.forEach((match: any) => {
        API.httpRequest(...).then((result) => {
            // Your logic here
            matches.push(yourLogicResult);
            complete++;
            if (complete === data.length) {
                resolve();
            }
        }
    }
};

console.log(matches); // still logs empty array

promise.then(() => console.log(matches)); // now logs the right array

You can solve this using other methods, for example Promise.all().

One very helpful way to solve it is using RxJs Observables. See https://www.learnrxjs.io/

Hope I helped you!

Upvotes: 0

Related Questions