【问题标题】:Using Async / Awaits within promise在 Promise 中使用 Async / Awaits
【发布时间】:2018-12-11 12:58:05
【问题描述】:

我的代码中有一个如下所示的承诺链:

  myPromise()
    .then(getStuffFromDb)
    .then(manipulateResultSet)
    .then(manipulateWithAsync)
    .then(returnStuffToCaller)

现在,在我的 manipulateWithAsync 中,我试图通过再次调用数据库来增强我的结果集,但它没有按我预期的那样工作,因为在调试时我发现控件移动到下一个returnStuffToCaller

的函数

下面是我的 manipulateWithAsync 函数的一个想法:

function manipulateWithAsync(rs) {
  return rs.map( async function whoCares(singleRecord) {
      let smthUseful = await getMoreData(singleRecord.someField);
      singleRecord.enhancedField = smthUseful;
      return singleRecord;
  })
}

我明白这种行为的重点:map 函数确实按预期工作,并且 promise 链不会对此表示怀疑,因为它不能与 awaits 一起使用。 有没有办法让我的 returnStuffToCaller 函数等到异步函数完成他的工作?

我也使用 bluebird,我尝试使用 coo-routine,所以如果你认为这是一个很好的解决方案,我会发布我的 bluebird coo-routine 失败代码:)

谢谢!

【问题讨论】:

  • return Promise.all(rs.map(...)) 但它可能有助于 return 映射函数中的某些内容,否则您将使用填充有 undefined 的数组来解析
  • 是的,我显然在我的地图中返回了一些东西。我在创建帖子时即时编写了代码,感谢您指出,马上编辑
  • 但是正如@PatrickRoberts 指出的那样,你需要有Promise.all,否则promise 会使用manipulateWithAsync 返回的数组来解析。
  • 确认,刚刚修改了我的代码,它工作正常。 @Patrick 如果您可以创建一个答案,我很乐意批准它。

标签: javascript node.js promise async-await bluebird


【解决方案1】:

问题在于使用 async/await 和 Array.map

这个答案应该会有所帮助:https://stackoverflow.com/a/40140562/5783272

【讨论】:

  • 是的,我的问题实际上是重复的
  • 这种情况下可以使用Promise.map(arr, fn)
【解决方案2】:

rs.map 迭代器跳转到下一个元素,而无需在每个单独的迭代中等待。 你需要像 asyncMap 这样的东西 您可以使用 - https://github.com/caolan/async 或者自己实现

async function asyncMap(array, cb) {
  for (let index = 0; index < array.length; index++) {
      return await cb(array[index], index, array);
  }
}

*cb 函数必须是异步函数

【讨论】:

  • 这个也可以,我认为更简单的改变是在地图上使用 forEach。谢谢!
【解决方案3】:

使用Promise.all 包裹您的地图,返回Promise,然后返回await 以获取任何您调用manipulateWithAsync 的结果。

// MOCKS FOR DEMO
// Test data used as input for manipulateWithAsync
const testData = [
  { recordNumber: 1 },
  { recordNumber: 2 },
  { recordNumber: 3 }
];

// Mock function which returns Promises which resolve after random delay ranging from 1 - 3 seconds
const getMoreData = () =>
  new Promise(resolve => {
    const calledAt = Date.now();
    setTimeout(() => {
      resolve({
        usefulData: `Promise called at ${calledAt}`
      });
    }, Math.floor(Math.random() * 3000) + 1000);
  });

// SOLUTION / ANSWER
const manipulateWithAsync = async rs =>
  Promise.all(
    rs.map(async singleRecord => {
      const smthUseful = await getMoreData(singleRecord.someField);

      // Instead of manipulating original data,
      // which might cause some unwanted side effects going forward,
      // instead return new objects
      return { ...singleRecord, enhancedField: smthUseful };
    })
  );

await manipulateWithAsync(testData);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-13
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 2013-07-17
    • 2019-05-24
    • 1970-01-01
    相关资源
    最近更新 更多