skip to Main Content

I’m working on a NestJSxMongoose store management project.

I have this piece of code in which I want to update some items in the database and put those updated items in an array that I will use later.

const updatedItems: Item[] = [];

purchaseData.items.forEach(async (purchasedItem) => {
  const itemInDB = await this.itemService.findItemByName(purchasedItem.name);

  itemInDB.quantity -= purchasedItem.quantity;

  const updatedItem = await this.itemService.updateItem(
    itemInDB['_id'],
    itemInDB
  );

  updatedItems.push(updatedItem);

  console.log(updatedItems); // Output : [{actual_data}]
});

console.log(updatedItems); // Output : []

The issue I have is that when I log the content of updatedItems inside the forEach(), it contains the actual expected data. But when I try to use it outside the forEach() loop, it logs an empty array. I want to use that array outside of the forEach().

What am I doing wrong ?

3

Answers


  1. If you want to wait for results, you have to write it like this: Get the array of all promises and awaits them.

    .forEach (as well as .map) runs synchronously. If you pass async function as a parameter, it does not await them, it just executes them to the nearest await and then returns (still unresolved) promise.

    Therefore the console.log(updatedItems); // Output : [] is executed before the logic inside async function.

    const updatedItems: Item[] = [];
    
    const promises = purchaseData.items.map(async (purchasedItem) => {
      const itemInDB = await this.itemService.findItemByName(purchasedItem.name);
    
      itemInDB.quantity -= purchasedItem.quantity;
    
      const updatedItem = await this.itemService.updateItem(
        itemInDB['_id'],
        itemInDB
      );
    
      updatedItems.push(updatedItem);
    
      console.log(updatedItems); // Output : [{actual_data}]
    });
    
    await Promise.all(promises);
    
    console.log(updatedItems); // Output : []
    

    Here you can see the order of execution:

    const purchaseData = { items: [1,2] }
    
    purchaseData.items.forEach(async (purchasedItem) => {
      console.log('first', purchasedItem);
      await console.log(); // the awaiting console log does nothing, it is just to trigger the beaviour of async function when it hits await
      console.log('third', purchasedItem);
    });
    
    console.log('second');
    Login or Signup to reply.
  2. Use Async and await its not waiting till the loop its going to next you need to wait until the loop finish

    async function updateItemFun() {
    const updatedItems: Item[] = [];
    
    await purchaseData.items.forEach(async (purchasedItem) => {
      const itemInDB = await this.itemService.findItemByName(purchasedItem.name);
    
      itemInDB.quantity -= purchasedItem.quantity;
    
      const updatedItem = await this.itemService.updateItem(
        itemInDB['_id'],
        itemInDB
      );
    
      updatedItems.push(updatedItem);
    
      console.log(updatedItems); // Output : [{actual_data}]
    });
    
    console.log(updatedItems); // Output : []
    }
    
    Login or Signup to reply.
  3. forEach expects a synchronous function. If an asynchronous callback is passed to it, the synchronous parts of the program (here, your second console.log) will be executed before executing the callback awaited lines. Pay attention to this link.

    It is better to put the whole iterative parts in an asynchronous function and use a for loop instead of forEach inside it, and then write the console.log after calling the asynchronous function.

    const updatedItems: Item[] = [];
    
    async function updateData(){
        for (let index = 0; index < purchaseData.items.length; index++) {
           const itemInDB = await this.itemService.findItemByName(purchaseData.items[index].name);
    
           itemInDB.quantity -= purchasedItem.quantity;
    
           const updatedItem = await this.itemService.updateItem(
               itemInDB['_id'],
               itemInDB
           );
    
           updatedItems.push(updatedItem);
    
           console.log(updatedItems);
       }
    }
    
    await updateData();
    console.log(updatedItems);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search