【问题标题】:Async/await always returns a promise or undefined异步/等待总是返回一个承诺或未定义
【发布时间】:2021-12-05 08:49:41
【问题描述】:

我一直在努力理解这有什么问题,但我仍然无法意识到我做错了什么。 我正在尝试使用此 .map() 函数将用户购物篮中的每个项目作为 orderItem 添加到数据库中(数据库中的 orderItem 对应于产品,这与问题并不真正相关,但如果你是难以理解操作):

const orderItems= orderData.map(async product=>{
          const productId=product.id.slice(0,product.id.length-5)

          const targetProduct=await dataSources.ProductAPI.product(productId)

          const name=targetProduct.name
          const quantity=218327

          await dataSources.OrderItemAPI.createOrderItem(orderId,productId,name,quantity,{ttlInSeconds:60*20})
        })

然后,我尝试将上述数组 orderItems 中的每个 orderItem 映射到数据库中的实际产品,如下所示:

//我们找到每个orderItem对应的产品

 const productsCorrespondingToOrderItems= orderItems.map(async orderItem=>{
      const trial=await orderItem
      console.log(trial) <--- returns undefined
      // OR just logging orderItem returns a promise
      await dataSources.TransactionAPI.findProductFromOrderItem(orderItem.productId).then(x=>console.log(x))
    })

我已经检查了订单商品中的每件商品,看起来还不错。问题是productsCorrespondingToOrderItems 中的每个orderItem 在我只是记录它时返回一个promise,或者如果我等待它则返回undefined。我真的不明白,我做错了什么?非常感谢!

【问题讨论】:

  • 你没有从你的map()回调中返回任何东西
  • @RobbyCornelissen 非常感谢您的快速回复!我不知道我是怎么错过的,现在就试试看!
  • 您尝试做的事情没有多大意义。 Array.map 不适用于异步代码。 Array.map 仅用于同步代码。如果你想使用async/await 进行顺序循环,你应该使用forfor ... of 循环。如果你想做并行异步操作,你应该使用 Array.map 创建你的 Promise,然后使用 Promise.all 等待它们。
  • @nicholaswmin - 这对于我们map 来说是非常常见的,带有async 回调来产生一系列你然后等待的承诺(例如,通过@987654336 @ 或其他 Promise 组合方法之一)。
  • @T.J.Crowder 确实是的,但我已经在评论的最后部分提到了这一点。

标签: javascript node.js asynchronous async-await


【解决方案1】:

您没有从地图中返回任何内容,并且地图不适用于异步/等待。改为一次调用 api 一次(串行)。如果您想同时(并行)等待多个 api 调用,请使用 TJ Crowder 的答案。

const orderItems= [];
for (const product of orderData) {
      const productId=product.id.slice(0,product.id.length-5)

      const targetProduct=await dataSources.ProductAPI.product(productId)

      const name=targetProduct.name
      const quantity=218327

      await dataSources.OrderItemAPI.createOrderItem(orderId,productId,name,quantity,{ttlInSeconds:60*20})
    })
    // push something to the orderItems array here!
}

【讨论】:

  • 非常感谢!!
【解决方案2】:

async 函数总是返回一个承诺。您不会从 map 回调中返回任何内容,因此由于回调是 async 函数,它们返回由 undefined 实现的承诺。

如果您想等待您的 map 操作中的所有承诺得到履行,请在结果上使用 Promise.allPromise.all 返回一个承诺,该承诺将通过您给它的承诺的履行值数组来履行(如果它们全部履行)或在其中任何一个第一次拒绝时被拒绝。您可以使用await(在async 函数中)或调用.then/.catch 来等待该承诺。

这是一个示例,假设您正在执行 map 的代码不在 async 函数中:

// If not in an `async` function
Promise.all(orderData.map(async product => {
    const productId = product.id.slice(0, product.id.length - 5);
    const targetProduct = await dataSources.ProductAPI.product(productId);
    const name = targetProduct.name;
    const quantity = 218327;

    const orderItem await dataSources.OrderItemAPI.createOrderItem(
        orderId,
        productId,
        name,
        quantity,
        { ttlInSeconds: 60 * 20 }
    );
    return await dataSources.TransactionAPI.findProductFromOrderItem(orderItem.productId);
}))
.then(productsCorrespondingToOrderItems => {
    // ...use `productsCorrespondingToOrderItems` here...
})
.catch(error => {
    // ...handle/report error...
});

请注意,这是并行工作的。如果您想串联,请使用async 函数和for-of 循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-10
    • 2018-04-30
    • 1970-01-01
    • 2022-10-30
    • 2019-03-20
    • 2020-02-19
    • 1970-01-01
    • 2017-12-07
    相关资源
    最近更新 更多