[英]Async/Await with map or foreach
我试图从我的数据库中检索一堆产品价格,并假设我可以通过它们映射或 foreach,并将价格 += 到一个变量上,如下所示:
// Get Total
exports.getTotal = (req,res) => {
let productList = req.body;
let total = 0;
const results = productList.map(async (product) => {
Product.findById(product._id)
.select('price')
.exec((err, foundProduct) => {
if (err){
console.log(`Error: Product with id ${product._id} not found.`);
} else {
console.log('Product price. ', foundProduct.price);
total += foundProduct;
}
})
});
Promise.all(results).then(data => console.log('Total is', total));
};
然而,总的console.log 总是返回0。我怀疑console.log 在映射和数据库查找承诺完成之前运行的问题。
任何指导表示赞赏。
您以错误的方式使用 exec Exec 会给您一个承诺。 你可以简化这个
// Get Total
exports.getTotal = (req, res) => {
const productList = req.body;
let total = 0;
const results = productList.map(async product => {
const foundProduct = await Product.findById(product._id).exec();
total += foundProduct;
return foundProduct;
});
Promise.all(results).then(data => console.log("Total is", total));
};
你忘了等待异步函数await Product.findById(product._id)
。
此外,通过使用数组减少,以功能方式编写可以消除此类任务的混乱。
// Get Total
exports.getTotal = (req, res) => {
const results = req.body.reduce(async (total, product) => {
await Product.findById(product._id)
.select('price')
.exec((err, foundProduct) => {
if (err){
console.log(`Error: Product with id ${product._id} not found.`);
return total
} else {
console.log('Product price. ', foundProduct.price);
return total += foundProduct;
}
})
}, 0);
Promise.all(results).then(data => console.log('Total is', data));
};
Array 的map()
、 foreach()
和其他迭代方法不使用 promise。 因此,使回调async
不会使内部迭代在对回调进行下一次迭代调用之前等待。 此外,您的地图将充满永远不会得到解决的承诺,因为您永远不会返回任何东西,这相当于拥有
Promises.all([new Promise(), new Promise(), new Promise()])
您可以更改代码以创建新承诺的正确映射,然后在获取所有内容后计算总数。 请注意,由于exec()
本身返回一个承诺,您只需返回:
const results = productList.map(product=> {
return Product.findById(product._id).select('price').exec();
});
Promise.all(results).then(values => {
let total = values.reduce((a, b) => a + b);
console.log(`Total: ${total}`)
});
您也可以在独立的async
函数中使用 for 循环并使用await
async function getTotal(){
let total = 0;
for(let product of productList){
let price = await Product.findById(product._id).select('price').exec();
total+=price;
}
return total;
}
getTotal().then(total=>console.log(`Total: ${total}`));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.