Throw inside a callback inside a promise [duplicate]
Asked Answered
P

1

5

I know that stackoverflow is full of similar question and I've read a lot of them.

From what I got a throw inside a promise should reject it, as I can read in the documentation:

If the executor throws an exception, its value will be passed to the reject resolving function.

But even after read a lot of post about promises and throw I still don't understand the snippet of code I'm pasting and why it happens.

function foo(a, b, cb) {
  setTimeout(() => {
    cb('Inner error *!?"$%&#@"');
  }, 0);
}

const getThePromise = () => {
  return new Promise((resolve, reject) => {
    const cb = (err) => {

      /* >>> ************ */

      throw err;       // catch not called
      // reject(err);  // catch called

      /* ************ <<< */

    }
    foo('foo', 'dudee', cb);
  });
}

getThePromise()
.catch((err) => {
  console.log('CATCH:', err);
})
.then((res) => {
  console.log('then...');
})

I don't understand why if I use the throw the .catch of the promise is not called but if I use the reject it is called.

Just for sake of clarification I'm using Node.js v6.2.2 in a Mac OS/X 10.11 but I don't think it could be also a browser issue.

Perceptual answered 31/8, 2016 at 9:15 Comment(5)
Put .error((err) => { console.log('ERROR:', err); }) too thereBlimey
@Shaharyar, native Promise.prototype doesn't have error functionBankroll
throw rejects promise if it's called synchronously only. remove your setTimeout and it will work. In async case use reject.Spermatocyte
"If the executor throws an exception" - not your case. Your executor doesn't throw. Try new Promise(() => {throw new Error('test')}).catch( e => console.log(e))Retinue
Why do you want to Throw the error? That is the whole point of the reject method.Kistner
C
8

You are throwing your error inside an asynchronous setTimeout call, which will lead to an uncaught error. The asynchronous code will not execute in the same context as the try-catch block. This has nothing to do with the promise API. This is just part of the behavior of asynchronous code execution in JavaScript.

Take a look at the following example.

const asyncOperation = err => {
  try {
    setTimeout(function() {
      throw err; // will be dropped onto the event queue
      // until the call stack is empty
      // even if this takes longer than
      // a second.
    }, 1000);
  } catch (e) {
    console.log(e) // will not be called
  }
}

asyncOperation('Inner error *!?"$%&#@"')

And now the same example with the try-catch block inside the setTimeout call and the error being thrown inside the try block.

const asyncOperation = err => {
  setTimeout(function() {
    try {
      throw err // here the error will be throw inside
    } catch (e) { // the try block and has the same execution 
      console.log(e) // context.
    }
  }, 1000);
}

asyncOperation('Inner error *!?"$%&#@"')

You can find more information regarding the Promise.catch right here.

Promise.prototype.catch()

The catch() method returns a Promise and deals with rejected cases only.

There is actually an example with the same situation you are describing in your example. Check out

Gotchas when throwing errors

// Errors thrown inside asynchronous functions will act like uncaught errors
var p2 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    throw 'Uncaught Exception!';
  }, 1000);
});

p2.catch(function(e) {
  console.log(e); // This is never called
});
Chubby answered 31/8, 2016 at 10:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.