如何在回调函数中设置新属性或使用 async 和 await 推送到数组?

Pha*_*nra 0 javascript meteor vue.js

当我将 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
Run Code Online (Sandbox Code Playgroud)

Fre*_*ark 6

问题在这里:

data.forEach(async item => {
Run Code Online (Sandbox Code Playgroud)

异步函数在调用时立即返回承诺,因此 forEach 完成并移至该console.log行。

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

由于您似乎已经在 async 函数中(因为您在代码中使用了更高的 await ),您可以等待所有的承诺解决awaitPromise.all

Promise.all期望一个承诺数组,所以forEach我们可以用它map来创建一个承诺数组

await Promise.all( data.map(async item => { ...
Run Code Online (Sandbox Code Playgroud)

forEach,map将迭代所有项目并运行给定的函数。与forEach,map将返回一个包含这些函数结果的数组,并且鉴于它们是异步函数,每个函数都将返回一个承诺。

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

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