1

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

Salman Arshad
  • 343
  • 6
  • 23
  • That `throw e;` is not threw outside of `.forEach`. I find hard to explain how it works. Try to read about `lambda`, what exactly do. Maybe this will help: https://www.vinta.com.br/blog/2015/javascript-lambda-and-arrow-functions/ – KunLun May 07 '20 at 20:35
  • `forEach` is a function which call your implementation. In `forEach`, I'm most sure, is a try-catch which absorbs all implementation mistakes(like exceptions, even if you throw it) to not break `forEach`. – KunLun May 07 '20 at 20:42
  • 1
    @KunLun No. You can easily throw exceptions from the callback to stop `forEach`. It's returning promises which will reject later that won't help. – Bergi May 07 '20 at 21:50

1 Answers1

1

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().

robinsax
  • 1,195
  • 5
  • 9