如何在回调函数中设置新属性或使用异步和等待推送到数组?
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
行。
此时委托给异步函数的异步工作尚未完成,因此数据尚未修改。
因为你似乎已经在一个异步函数中(因为你在代码中使用了更高的等待),你可以等待所有的承诺解决 await
和 Promise.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');
}
})
);
}
当我将 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
行。
此时委托给异步函数的异步工作尚未完成,因此数据尚未修改。
因为你似乎已经在一个异步函数中(因为你在代码中使用了更高的等待),你可以等待所有的承诺解决 await
和 Promise.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');
}
})
);
}