Home > Blockchain >  Why promise reject does not handle an error
Why promise reject does not handle an error

Time:11-10

I'm using nodejs request package (2.88 version) with node v10.24.1

The Promise below does not handle an error if the url simply was not specified. I'm getting UnhandledPromiseRejectionWarning and from the request package source I can see an exception thrown for that case.

If I remove the async keyword everything works fine, and the reject handled.

return new Promise(async (resolve, reject) => {
   request(uri: url).on('error', err => {
      reject();
   }).on('response', response => {
      resolve();
   });
});

Could you please explain what happens. Probably the request's exception finished before the reject actually fired. Any details please.

CodePudding user response:

When you pass a function to new Promise, this function gets immediately executed.

There's no magic here, for the purpose of illustration, the constructor of new Promise() might look a bit like this:

class Promise {
  constructor(executor) {
    executor(this.resolveFunction, this.rejectFunction); 
  }
}

So this example:

new Promise(() => {
  console.log(1);
});
console.log(2);

Outputs:

1
2

This is important, because if you pass something to new Promise that throws an exception, this happens immediately too:

new Promise((res, rej) => {
  throw new Error('foo');
});

The error thrown here doesn't cause the promise to be rejected, it completely prevents new Promise() from succeeding. No promise is returned, and the exception is thrown in the outer function that called new Promise().

However, this breaks down when you pass an async function:

new Promise(async (res, rej) => {
  throw new Error('foo');
});

Because of how async functions work, this error will not be thrown during the setup of new Promise(), but the async function you passed will handle the error asyncronously and returns a rejected promise, that new Promise() doesn't know how to handle.

This is no different from calling an async function directly yourself and not handling errors:

(async () => {
  throw new Error('foo');
})();

So the reason things are failing have less to do with new Promise(), but more with the fact how async functions work in general.

Just a last time for future readers, you should never pass an async executor to new Promise(), because:

  • The only reason you need async at all is so you can use await.
  • await only works with promises.
  • If you already had a promise you wanted to await, you didn't need new Promise() to begin with, because the main use-case of new Promise is to convert something that doesnt use promises into something that does.
  • Related