Home > Back-end >  Async/await always returns a promise or undefined
Async/await always returns a promise or undefined

Time:10-18

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!
}
  • Related