Search code examples
javascriptasynchronouspromiseasync-awaites6-promise

Javascript forEach swallowing exceptions


I am trying to loop over an array using forEach loop with async callback in javascript. The problem is that when I throw an exception it gives

(node:2500) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 6)

Although I have a catch block after forEach. Here is my code

async function func() {
    try {
        array.forEach(async (e) => {
            try {
                let bom = await BOMChild.findOne({
                    where: { id: e.id },
                });

                if (bom.BOMProductId || bom.BOMProductId === 0) {
                    throw {
                        name: " error",
                        description: `Description `,
                    };
                }
            } catch (e) {
                throw e;
            }
        });
    } catch (e) {
        //exception caught
    }
}

What I am doing wrong and what is the possible way to solve this. TIA


Solution

  • Unfortunately there's no safe way to use async callbacks with forEach. The simplest solution is to re-implement forEach in an async way as shown below. Note that asyncForEach itself returns a promise, so you'll need to use .then() to continue your program.

    const asyncForEach = async (array, callback) => {
      try {
        for (let i = 0; i < array.length; i++) {
          await callback(array[i]);
        }
      }
      catch (ex) {
         // handle exception here.
      }
    }
    
    asyncForEach(array, async () => {
      let bom = await BOMChild.findOne({
        where: { id: e.id },
      });
    
      if (bom.BOMProductId || bom.BOMProductId === 0) {
        throw {
          name: " error",
          description: `Description `,
        };
      }
    }).then(() => {
      // continue program.
    });
    

    If you want to test your promise chops with a cleaner, but more confusing solution, take a look a Promise.all().