【问题标题】:async await in forEach [duplicate]forEach中的异步等待[重复]
【发布时间】:2017-01-11 16:36:59
【问题描述】:

我有以下按预期工作的功能:

  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 的主体中调用一个异步函数,如下所示:

  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 以同步方式执行。我可以重构生成器吗?

【问题讨论】:

  • "这显然会破坏函数,因为 forEach 现在正在异步执行" --- 它不会改变任何东西。 Array.prototype.forEach 不希望接受 async 函数,因此它将作为“正常”函数调用它。所以所有的函数都会被立即调用。
  • “有没有办法我可以使用异步等待 forEach 以同步方式执行” --- 只需使用 forfor-of 循环遍历数组。您还必须将 createObjectFrom 更改为 async
  • 这种东西你可以用this one顺利搞定,不介意用模块试试看。

标签: javascript node.js ecmascript-2017


【解决方案1】:

你不能强制一个普通的 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;
}

但是,如果您想为每个项目执行诸如 fetch 之类的异步操作,请执行以下操作:

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

  return subDataArr;
}

【讨论】:

  • 对于 foreach 的每次迭代,我都需要 s knex 调用。我很好奇这是如何在节点中处理的,因为它似乎很常见的用例
  • @dagda1 这基本上是我的最后一个代码示例。假设 loadSubData 是 Knex 调用。
猜你喜欢
  • 2019-06-29
  • 2019-01-15
  • 2016-12-05
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 2021-08-23
  • 2020-10-20
相关资源
最近更新 更多