Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Promise doesn't reject when throwing an error

According to this Stack Overflow answer here, there is no difference between using reject and throw within a promise to trigger a rejection.

However, I have found that, depending on the structure of an external module, throwing an error doesn’t always trigger the catch block.

This is my code in index.js:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

try {
  const service = require('./services/patreon.js');
  await service.start();
} catch(err) {
  console.log('Caught!');
}

And here is my code in patreon.js:

function start() {
  return new Promise(async (resolve, reject) => {
    throw new Error('Oh no!');
  });
}

module.exports = {
  start: start
}

My expected behavior is that my try/catch block would handle the thrown error and I would see "Caught!" in my console ouput. Instead, my try/catch does not handle the error and I end up with an unhandledRejection.

Interestingly, if I re-structure my module.exports in patreon.js I can fix this and my try/catch block will handle the error:

Update index.js:

try {
  const service = require('./services/patreon.js');
  await service();
} catch(err) {
  console.log('Caught!');
}

Update patreon.js:

module.exports = () => {
  return new Promise(async (resolve, reject) => {
    throw new Error('Oh no!');
  });
}

With the above updates, my try/catch works perfectly but I no longer have the ability to export more than just a function.

The other solution is to simply reject() the promise instead of throw – and this works fine in both examples but for personal preference and code cleanliness I would rather be able to throw.

So my question is, why can’t I use throw when my module is structured in the way shown in my first example? In both cases, I end up with the exact same thing: a function that returns a promise.

>Solution :

The reason your first example is not working as expected is due to the way you’re creating the Promise within an async function. In your first example, you have the following:

function start() {
  return new Promise(async (resolve, reject) => {
    throw new Error('Oh no!');
  });
}

Here, you’re passing an async function as the executor for the Promise constructor. Async functions always return a promise, so in this case, you have a promise inside another promise. When you throw an error inside the async function, it is only caught by the inner promise, not the outer one, which leads to an unhandled rejection.

In your second example, you’ve simplified your code, and the problem disappears because you no longer have an unnecessary async function:

module.exports = () => {
  return new Promise(async (resolve, reject) => {
    throw new Error('Oh no!');
  });
}

However, you can still achieve your desired behavior without losing the ability to export more than one function from your module. To fix the issue, you can make the start() function itself an async function instead of the promise executor:

// patreon.js
async function start() {
  throw new Error('Oh no!');
}

module.exports = {
  start: start
}

Now, when you throw an error in the start() function, it will be caught by the try/catch block in your index.js file:

// index.js
try {
  const service = require('./services/patreon.js');
  await service.start();
} catch(err) {
  console.log('Caught!');
}

By making the start() function async, you’re ensuring it returns a promise, which will be rejected if an error is thrown inside the function. This way, you can use the try/catch block to handle the error, and you can continue to export multiple functions from your module.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading