I have the following fiddle: http://jsfiddle.net/thelgevold/3uv9nnjm/6/
angular.module(\'hello\',[]).controller(\'helloController\',function($q){
    console.cl         
        
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.
.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.