async await in forEach

async await in forEach

本文关键字:forEach in await async      更新时间:2023-09-26

我有以下函数,按预期工作:

  createObjectFrom(record) {
    let obj = {};
    this.opts.transformers.forEach((transformer, index) => {
      const headerIndex = findIndex(this.headers, (header) => {
        return header === transformer.column;
      });
      const value = transformer.formatter(record[headerIndex]);
      obj[transformer.field] = value;
    });
    return obj;
  }

我想重构它,使用async await,并在forEach函数体中调用一个async函数,像这样:

  createObjectFrom(record) {
    let obj = {};
    this.opts.transformers.forEach(async (transformer, index) => {
      const headerIndex = findIndex(this.headers, (header) => {
        return header === transformer.column;
      });
      const result = await this.knex('managers').select('name')
      console.log(result);
      const value = transformer.formatter(record[headerIndex]);
      obj[transformer.field] = value;
    });
    return obj;
  }

这显然会破坏函数,因为forEach现在是异步执行的,函数只会执行并离开。

是否有一种方法,我可以使用异步等待forEach以同步方式执行。我可以重构到生成器吗?

你不能强制一个普通的JS函数等待异步行为。不可能!

所以你必须重构你的createObjectFrom为异步的。然后用map/reduce代替forEach。为了提高性能,您不希望这样做:

for(transformer of this.opts.transformers) {
    await this.knex('managers').select('name');
}

你应该使用await Promise.all(...)

但是在您的情况下,对knex的调用似乎不依赖于转换器,因此您可以这样做:

async createObjectFrom(record) {
  let obj = {};
  const result = await this.knex('managers').select('name')
  this.opts.transformers.forEach(async (transformer, index) => {
    const headerIndex = findIndex(this.headers, (header) => {
      return header === transformer.column;
    });
    console.log(result);
    const value = transformer.formatter(record[headerIndex]);
    obj[transformer.field] = value;
  });
  return obj;
}

然而,如果你想做一些事情,比如对每个项目进行异步取回,那么就像这样做:

async foo(data) {
  const subDataArr = await Promise.all(data.map(record => loadSubData(record)));
  return subDataArr;
}