Home > Net >  How to await for an aync function in a for loop?
How to await for an aync function in a for loop?

Time:05-15

I have an aysnc function which loop thru an array, make another aync call for each element, wait for result.

public async myfetch(parent_id: string): Promise<Record[]> {
  let payload = await this.load(parent_id);
  let records = [];

  await payload.items.forEach(async (item: any) => {
        let child = await this.load_another_api(item.child_id);
        let record = {
               a: child.a,
               b: child.b,
        }
        records.push(record)
  }
  return records;
}

And signtgure of load, load_another_api are like:

public async load(Id: string): Promise<any> {
/// some logic to build requestUrl
        return fetch(requestUrl, options)
            .then((response) => { return response.json(); });
}

But when I debug, I see that myfetch function returns to the caller before all the for loop items have been called load_another_api and wait for the result and populate to records array.

Can you please tell me what am I missing?

CodePudding user response:

You can't make an asynchronous forEach loop. But, you have two workarounds here:

  1. Use a for loop instead:
public async myfetch(parent_id: string): Promise<Record[]> {
  let payload = await this.load(parent_id);
  let records = [];

  for (let index: number = 0; index < payload.items.length; index  ) {
    const item: any = payload.items[index];
    let child = await this.load_another_api(item.child_id);
    let record = {
      a: child.a,
      b: child.b
    };
    records.push(record);
  }
  return records;
}
  1. Wait for the forEach to finish with a Promise
public async myfetch(parent_id: string): Promise<Record[]> {
  let payload = await this.load(parent_id);
  let records = [];

  await new Promise<void>((resolve) => {
    payload.items.forEach(async (item: any, index: number) => {
      let child = await load_another_api(item.child_id);
      let record = {
        a: child.a,
        b: child.b
      };
      records.push(record);

      // Condition to resolve promise
      if (index == payload.items.length - 1) {
        resolve();
      }
    });
  });
  return records;
}

CodePudding user response:

You can do this using array.prototype.map and Promise.all instead. Something like this:

public async myfetch(parent_id: string): Promise<Record[]> {
  const payload = await this.load(parent_id);

  const promises = payload.items.map((item: any) => 
          this.load_another_api(item.child_id)
              .then((child: any) => ({a: child.a, b: child.b})));

  return Promise.all(promises);
}
  • Related