当我用asyncawait和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 => {
async函数在被调用后会立即返回承诺 所以forEach完成后就会继续执行 console.log
行。
此时委托给异步函数的异步工作还没有完成,所以数据还没有被修改。
由于你似乎已经在一个异步函数中了(因为你在代码中使用了更高的 await),你可以等待所有的承诺用 await
和 Promise.all
Promise.all
期待一个数组的承诺,所以用了 forEach
我们可以用 map
以创建一个承诺数组
await Promise.all( data.map(async item => { ...
喜欢 forEach
, map
将遍历所有的项目并运行给定的函数。与 forEach
, map
将返回一个包含这些函数结果的数组,鉴于它们是async函数,每个函数将返回一个承诺。
现在我们使用 Promise.all
来创建一个单一的承诺,这个承诺将在每个异步函数完成后解析。而我们使用 await
来告诉函数暂停,直到新的承诺解决。
暂停函数,用 await
意味着 console.log 不会运行,直到每一个 async 函数完成,这意味着当它运行时,它将有正确的数据。
这是一个工作实例,需要的人可以看看。
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');
}
})
);
}