在异步映射中推送到数组
Pushing to array in asynchonous map
我知道这个问题已经有人问过,但我无法正确回答。尝试使用承诺但无济于事。当控制台记录 req.user items 仍然是一个空数组。我知道我应该使用 promises 但我在实现它时遇到了麻烦。帮助赞赏
app.get('/cart',checkAuthenticated, async (req, res) => {
if(req.user.cart.length > 0){
req.user.items = []
req.user.cart.map(async (item) => {
var itemDescription = await productsModel.findOne({id: item.itemId})
req.user.items.push(itemDescription)
});
console.log(req.user)
}
它为空的原因是您没有等待映射中的所有异步函数完成。试试这个:
await Promise.all(req.user.cart.map(async (item) => {
var itemDescription = await productsModel.findOne({id: item.itemId})
req.user.items.push(itemDescription)
}));
请注意,@jfriend00 已评论此实现将不保证 req.user.items 中项目的顺序。
因为您已经在使用地图,所以执行以下操作会更简单,而且还能保证项目的顺序:
req.user.items = await Promise.all(req.user.cart.map(async (item) => {
var itemDescription = await productsModel.findOne({id: item.itemId})
return itemDescription;
}));
.map()
不是 promise-aware。它不会注意您的 async
回调函数 returns 的承诺。因此,一旦您点击 await productsModel.findOne(...)
,async
函数 returns 一个未实现的承诺,并且 .map()
前进到循环的下一次迭代。
有很多不同的方法可以解决这个问题。如果你想使用.map()
,那么你需要注意你的回调是这样返回的承诺:
app.get('/cart', checkAuthenticated, async (req, res) => {
if (req.user.cart.length > 0) {
req.user.items = await Promise.all(req.user.cart.map((item) => {
return productsModel.findOne({ id: item.itemId });
}));
console.log(req.user)
}
});
以上实现将尝试运行所有数据库并行查找。
一个更简单的实现只是使用一个简单的 for
循环和 运行 数据库一次查找一个:
app.get('/cart', checkAuthenticated, async (req, res) => {
if (req.user.cart.length > 0) {
req.user.items = [];
for (let item of req.user.cart) {
req.user.items.push(await productsModel.findOne({ id: item.itemId }));
}
console.log(req.user)
}
});
在您的示例中,数组仍然是空的,因为 map 函数中的回调是异步工作的,因此您需要等待代码完成。因为 map 函数 returns promises 数组,它们都需要使用 Promise.all:
来解决
app.get('/cart', checkAuthenticated, async (req, res) => {
if (req.user.cart.length > 0) {
req.user.items = []
const promises = req.user.cart.map(async (item) => {
var itemDescription = await productsModel.findOne({ id: item.itemId })
req.user.items.push(itemDescription)
});
await Promise.all(promises);
console.log(req.user)
}
});
否则,你可以用for循环替换map函数:
app.get('/cart', checkAuthenticated, async (req, res) => {
if (req.user.cart.length > 0) {
req.user.items = []
for (const item of req.user.cart) {
var itemDescription = await productsModel.findOne({ id: item.itemId })
req.user.items.push(itemDescription)
}
console.log(req.user)
}
});
我知道这个问题已经有人问过,但我无法正确回答。尝试使用承诺但无济于事。当控制台记录 req.user items 仍然是一个空数组。我知道我应该使用 promises 但我在实现它时遇到了麻烦。帮助赞赏
app.get('/cart',checkAuthenticated, async (req, res) => {
if(req.user.cart.length > 0){
req.user.items = []
req.user.cart.map(async (item) => {
var itemDescription = await productsModel.findOne({id: item.itemId})
req.user.items.push(itemDescription)
});
console.log(req.user)
}
它为空的原因是您没有等待映射中的所有异步函数完成。试试这个:
await Promise.all(req.user.cart.map(async (item) => {
var itemDescription = await productsModel.findOne({id: item.itemId})
req.user.items.push(itemDescription)
}));
请注意,@jfriend00 已评论此实现将不保证 req.user.items 中项目的顺序。
因为您已经在使用地图,所以执行以下操作会更简单,而且还能保证项目的顺序:
req.user.items = await Promise.all(req.user.cart.map(async (item) => {
var itemDescription = await productsModel.findOne({id: item.itemId})
return itemDescription;
}));
.map()
不是 promise-aware。它不会注意您的 async
回调函数 returns 的承诺。因此,一旦您点击 await productsModel.findOne(...)
,async
函数 returns 一个未实现的承诺,并且 .map()
前进到循环的下一次迭代。
有很多不同的方法可以解决这个问题。如果你想使用.map()
,那么你需要注意你的回调是这样返回的承诺:
app.get('/cart', checkAuthenticated, async (req, res) => {
if (req.user.cart.length > 0) {
req.user.items = await Promise.all(req.user.cart.map((item) => {
return productsModel.findOne({ id: item.itemId });
}));
console.log(req.user)
}
});
以上实现将尝试运行所有数据库并行查找。
一个更简单的实现只是使用一个简单的 for
循环和 运行 数据库一次查找一个:
app.get('/cart', checkAuthenticated, async (req, res) => {
if (req.user.cart.length > 0) {
req.user.items = [];
for (let item of req.user.cart) {
req.user.items.push(await productsModel.findOne({ id: item.itemId }));
}
console.log(req.user)
}
});
在您的示例中,数组仍然是空的,因为 map 函数中的回调是异步工作的,因此您需要等待代码完成。因为 map 函数 returns promises 数组,它们都需要使用 Promise.all:
来解决app.get('/cart', checkAuthenticated, async (req, res) => {
if (req.user.cart.length > 0) {
req.user.items = []
const promises = req.user.cart.map(async (item) => {
var itemDescription = await productsModel.findOne({ id: item.itemId })
req.user.items.push(itemDescription)
});
await Promise.all(promises);
console.log(req.user)
}
});
否则,你可以用for循环替换map函数:
app.get('/cart', checkAuthenticated, async (req, res) => {
if (req.user.cart.length > 0) {
req.user.items = []
for (const item of req.user.cart) {
var itemDescription = await productsModel.findOne({ id: item.itemId })
req.user.items.push(itemDescription)
}
console.log(req.user)
}
});