首页 > 解决方案 > 如何在回调函数中设置新属性,或使用异步和等待推送到数组?

问题描述

当我将 async/await 与 rawCollection 一起使用并在循环内获取数据,然后设置新属性 (poTmp) 时,它按预期工作。但是在我在外面设置新属性和 console.log 之后,它并没有设置新的道具。为什么?

let items = await Items.rawCollection()
    .aggregate([
      {
        $match: match,
      },
    ])
    .toArray()

  let data = items
  data.forEach(async item => {
    let po = await PurchaseOrderDetails.rawCollection()
      .aggregate([
        {
          $match: {
            itemId: item._id,
            tranDate: { $lte: tDate },
          },
        },
        {
          $group: {
            _id: '$itemId',
            itemDoc: { $last: item },
            onHandPO: { $sum: '$qtyBase' },
          },
        },
        {
          $group: {
            _id: '$itemId',
            itemDoc: { $last: '$itemDoc' },
            lastOnHandPO: { $last: '$onHandPO' },
          },
        },
      ])
      .toArray()
    //==================
    //set new properties
    //==================
    item.poTmp = po[0]

  })
  console.log(data)
  return data

标签: javascriptmeteorvue.js

解决方案


问题在这里:

data.forEach(async item => {

async 函数在调用时立即返回 Promise,因此 forEach 完成并继续执行console.log

此时委派给异步函数的异步工作尚未完成,因此尚未修改数据。

由于您似乎已经在一个异步函数中(因为您在代码中使用了更高的 await),您可以等待所有的 Promiseawait解决Promise.all

Promise.all需要一个 promise 数组,所以forEach我们可以使用map创建一个 promise 数组来代替

await Promise.all( data.map(async item => { ...

Like forEach,map将遍历所有项目并运行给定的函数。与, 不同forEachmap将返回一个包含这些函数结果的数组,并且鉴于它们是异步函数,每个函数都将返回一个 Promise。

现在我们Promise.all用来创建一个单一的 Promise,它将在每个异步函数完成时解析。我们await用来告诉函数暂停,直到新的承诺解决。

暂停函数await意味着 console.log 在每个异步函数都完成之前不会运行,这意味着它在运行时将拥有正确的数据。


推荐阅读