Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the 'catch' work in a native Promise chain?

Try this piece of code on console tab of Chrome or Firefox

var p = new Promise(function(resolve, reject) {
    setTimeout(function() {
        reject(10);
    }, 1000)
})

p.then(function(res) { console.log(1, 'succ', res) })
.catch(function(res) { console.log(1, 'err', res) })
.then(function(res) { console.log(2, 'succ', res) })
.catch(function(res) { console.log(2, 'err', res) })

The result will be

1 "err" 10
2 "res" undefined

I've tried many other examples but it seems that the first then() returns a promise that always resolves and never rejects. I've tried this on Chrome 46.0.2490.86 and Firefox 42.0. Why does this happen? I thought that then() and catch() can be chain multiple times?

like image 745
KwiZ Avatar asked Dec 11 '15 11:12

KwiZ


2 Answers

Just like in the synchronous code:

try { 
    throw new Error();
} catch(e) {
    console.log("Caught");
}
console.log("This still runs");

Code that runs after the exception has been handled will run - this is because exceptions are an error recovery mechanism. By adding that catch you signaled that the error has been handled. In the synchronous case we handle this by rethrowing:

try { 
    throw new Error();
} catch(e) {
    console.log("Caught");
    throw e;
}
console.log("This will not run, still in error");

Promises work similarly:

 Promise.reject(Error()).catch(e => {
      console.log("This runs");
      throw e;
 }).catch(e => {
      console.log("This runs too");
      throw e;
 });

As a tip - never reject with non-Errors as you lose a lot of useful stuff like meaningful stack traces.

like image 173
Benjamin Gruenbaum Avatar answered Oct 20 '22 05:10

Benjamin Gruenbaum


Why does this happen? I thought that then() and catch() can be chain multiple times?

@Benjamin is right, +1, but to put it in another way, these are the rules:

  • If you add then multiple times, you are chaining methods that should be called in sequence, until an exception is thrown. Exceptions in the then chain must be handled by catch declared after the then. If there's no catch after the then, this error will be triggered: Uncaught (in promise) Error(…).
  • If you add catch multiple times, you are chaining methods that should be called when something goes wrong (in the then functions before). However, the second catch in the chain will only be called if the first one re-throw the exception, and so forth.
  • When catch is triggered, the chain resumes on the next then declared after the catch.
like image 37
André Pena Avatar answered Oct 20 '22 05:10

André Pena