如何在回调函数中设置新属性或使用异步和等待推送到数组?

How to set new properties, or push to array with async and await, within callback function?

当我将 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

问题在这里:

data.forEach(async item => {

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

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

因为你似乎已经在一个异步函数中(因为你在代码中使用了更高的等待),你可以等待所有的承诺解决 awaitPromise.all

Promise.all 需要一组承诺,因此我们可以使用 map 来创建一组承诺

而不是 forEach
await Promise.all( data.map(async item => { ...

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

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

await 暂停函数意味着 console.log 不会 运行 直到每个异步函数都完成,这意味着它会在完成时获得正确的数据 运行.

这是一个工作示例,任何需要它的人:

  public async updateBatch(req:any,res:any){

        body = [1,3,4,5,6]

        var rfinal:number[] = [];

        await Promise.all(body.map(async items=>{

            let newStatus = 'MJ';

                inputParameters = [
                { name: 'PID', dataType: sql.Int, value: items },
                { name: 'Status', dataType: sql.VarChar, value: newStatus }
            ];

            let CustomQuery = `UPDATE MYTable 
                SET Status= @Status
                WHERE PID= @PID`;

            const result = await provider.executeQuery(CustomQuery, inputParameters).catch(err => {
                    LogErrors.logErrors(err);
            });
            if(result.rowsAffected[0]>0){
                    rfinal.push(result.rowsAffected[0]);
            }else{
                throw new console.error('Un expected error, updating newsfeed');
            }

        })
        );

  }