I have been struggling to understand what is wrong with this for a while, but I still cant realize what I am doing wrong. I am trying to add into the database each item of the user's basket as as an orderItem, with this .map() function (an orderItem in the database corresponds to a product, that is not really relevant for the question but helps if you are struggling to understand the operation) :
const orderItems= orderData.map(async product=>{
const productId=product.id.slice(0,product.id.length-5)
const targetProduct=await dataSources.ProductAPI.product(productId)
const name=targetProduct.name
const quantity=218327
await dataSources.OrderItemAPI.createOrderItem(orderId,productId,name,quantity,{ttlInSeconds:60*20})
})
Then, I am trying to map each orderItem from the above array orderItems
to an actual product in the database , like this:
//we find the product corresponding to each orderItem
const productsCorrespondingToOrderItems= orderItems.map(async orderItem=>{
const trial=await orderItem
console.log(trial) <--- returns undefined
// OR just logging orderItem returns a promise
await dataSources.TransactionAPI.findProductFromOrderItem(orderItem.productId).then(x=>console.log(x))
})
I have checked each item from order items and it looks alright. The problem is that each orderItem
in productsCorrespondingToOrderItems
returns eighter a promise, when I am simply logging it , or undefined if I await it. I really dont understand, what am I doing wrong? Thank you so much !
CodePudding user response:
async
functions always return a promise. You're not returning anything from your map
callbacks, so since the callbacks are async
functions, they return promises that are fulfilled with undefined
.
If you want to wait for all of the promises from your map
operations to be fulfilled, use Promise.all
on the result. Promise.all
returns a promise that will be fulfilled with an array of the fulfillment values of the promises you give it (if they're all fulfilled) or rejected the first time any of them rejects. You wait for that promise either with await
(in an async
function) or by calling .then
/.catch
on it.
Here's an example that assumes the code where you're doing that map
is not in an async
function:
// If not in an `async` function
Promise.all(orderData.map(async product => {
const productId = product.id.slice(0, product.id.length - 5);
const targetProduct = await dataSources.ProductAPI.product(productId);
const name = targetProduct.name;
const quantity = 218327;
const orderItem await dataSources.OrderItemAPI.createOrderItem(
orderId,
productId,
name,
quantity,
{ ttlInSeconds: 60 * 20 }
);
return await dataSources.TransactionAPI.findProductFromOrderItem(orderItem.productId);
}))
.then(productsCorrespondingToOrderItems => {
// ...use `productsCorrespondingToOrderItems` here...
})
.catch(error => {
// ...handle/report error...
});
Note that that does the work in parallel. If you want to do it in series instead, use an async
function and a for-of
loop.
CodePudding user response:
You did not return anything from your map and map does not work for async/await. Do this instead:
const orderItems= [];
for (const product of orderData) {
const productId=product.id.slice(0,product.id.length-5)
const targetProduct=await dataSources.ProductAPI.product(productId)
const name=targetProduct.name
const quantity=218327
await dataSources.OrderItemAPI.createOrderItem(orderId,productId,name,quantity,{ttlInSeconds:60*20})
})
// push something to the orderItems array here!
}