Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Executing then after catch

I have the following fiddle: http://jsfiddle.net/thelgevold/3uv9nnjm/6/

angular.module('hello',[]).controller('helloController',function($q){

    console.clear();
    function someService(){
       var deferred = $q.defer();
       deferred.reject({e:'error'}); 
       return deferred.promise;
    } 

    function callService(){
        return someService().then(function(obj){
           console.log('first then');
        }).
        catch(function(e){
            console.log('error1');
            var deferred = $q.defer();
            deferred.reject({e:'error'}); 
            return deferred.promise;
        });
    }

    callService().catch(function(e){
      console.log('error2');
    }).then(function(e){
      console.log('second then');
    });

});

It's essentially just a quick $q promise POC. My question is: Why does the last then clause get called when the promise is rejected? The output is as follows:

error1

error2

second then

I understand why error1/error2 are printed, but I thought the second then string should not be printed since the promise was rejected. I thought it would omit "second then" for the same reason the "first then" is omitted. Any thoughts?

like image 653
TGH Avatar asked Feb 11 '15 04:02

TGH


People also ask

Can I use then after catch?

If you return a normal value or a promise that eventually resolves from the . catch() handler (thus "handling" the error), then the promise chain switches to the resolved state and the . then() handler after the . catch() will be called.

Can we add then after catch in Promise?

The catch method is used for error handling in promise composition. Since it returns a Promise , it can be chained in the same way as its sister method, then() . catch() internally calls then() . This is observable if you wrap the methods.

How do you use catch and then?

In summary: then : when a promise is successful, you can then use the resolved data. catch : when a promise fails, you catch the error, and do something with the error information. finally : when a promise settles (fails or passes), you can finally do something.

Why then and catch both called?

The then callback gets called because the catch callback is before it, not after. The rejection has already been handled by catch . If you change the the order (i.e. ( promise.


1 Answers

Before I get started, don't do this:

var deferred = $q.defer();
deferred.reject({e:'error'}); 
return deferred.promise;

Do this:

return $q.reject({e:'error'});

Or preferably, this:

return $q.reject(new Error('error'));

Beware the deferred antipattern.

Now, for the answer to your question.


The .catch() after your call to callService() is catching the error and not producing a new error. It has essentially "handled" the error, and the following .then() handler is free to be called.

The synchronous code equivalent of your example would be:

function someService() {
  throw { e: 'error' };
}

function callService() {
  try {
    var obj = someService();
    console.log('first then');
  } catch (e) {
    console.log('error1');
    throw { e: 'error' };
  }
}

var e;
try {
  e = callService();
} catch (e) {
  console.log('error2');
}

console.log('second then');

I think that if you look at it this way, it makes perfect sense.

The relevant text in the Promises/A+ spec is here. For all intents and purposes, you can view the catch handler as the same thing as an onRejected handler:

2.2.7. then must return a promise [3.3].

promise2 = promise1.then(onFulfilled, onRejected);

2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).

Basically, your onRejected handler is "returning" the value undefined, so the promise produced by catch() resolves with the value undefined.

like image 94
JLRishe Avatar answered Oct 10 '22 05:10

JLRishe