在承诺内使用异步/等待

时间:2018-07-03 09:11:15

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

我的代码中有一个特定的promise链,如下所示:

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

现在,在我的 manipulateWithAsync 中,我试图通过再次调用DB来增强我的结果集,但是它没有按我预期的那样工作,因为在调试时我发现控件移至下一个函数是 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链对此不起作用,因为它不与等待对象一起工作。 有没有办法让我的 returnStuffToCaller 函数等待异步函数完成其工作?

我也使用bluebird,并且尝试使用coo-routine,因此,如果您认为这是一个很好的解决方案,我将发布我的bluebird coo-routine失败代码:)

谢谢!

3 个答案:

答案 0 :(得分:2)

问题在于对Array.map使用异步/等待

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

答案 1 :(得分:1)

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函数必须是异步的

答案 2 :(得分:1)

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);