1

In every $http call with .then(successFunc) and .catch(errFunc) (alternatively then(successFunc, errFunc) the then/success is always called (the promise is successfully resolved).

Example

$http.get('/some/resource') 
//   /some/resource --> HTTP 400
    .then(function(response)
    {
        console.log('success');
    })
    .catch(function(reason)
    {
        console.log('error');
    })

// Console: 
// - success

Is this the intended behaviour or what causes this?

2
  • This is not the default behaviour, but might be due to a response interceptor you have used in your application. Usually the response interceptors are global and you might not be aware of it's presence if it is a large application. Could you isolate this code in a fiddle to reproduce the same issue? Commented Sep 13, 2016 at 11:24
  • I created this as self-answered Q&A question to keep it around for other people since there was no similar question here on SO. You describe exactly the issue I wanted to point out with this post (also see my in-depth answer). Still thanks for the answer :) Commented Sep 15, 2016 at 12:30

2 Answers 2

1

No, this is not intended behaviour. Normally it should call .then() on HTTP 2xx and .catch() on HTTP 4xx and HTTP 5xx (not sure about the others).

The described behaviour is probably caused by another .catch() returning a resolved promise.

In a slightly changed example:

//In some Service:
function getResources()
{
    $http.get('/some/resource') 
    //   /some/resource --> HTTP 400
        .then(function(response)
        {
            console.log('service success');
            return response;
        })
        .catch(function(reason)
        {
            console.log('service error');
            // IMPORTANT: although this is returned 
            // in a .catch() it returns a resolved promise
            return reason;
        });
}

//In some Controller:
someService.getResources()
    .then(function(response)
    {
        console.log('controller success');
    })
    .catch(function(reason)
    {
        console.log('controller error');
    });


// Console:
// - service error
// - controller success

Note that this can also be caused by a registered http interceptor:

$httpProvider.interceptors.push(function($q)
{
    return {
        'response': function(response)
        {
            // do something
            return response;
        },
        'responseError': function(rejection)
        {
            // do something
            return rejection; // <-- this causes the problem
            // instead do
            return $q.reject(rejection);
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Your example converts a rejection to a resolved promise.

$http.get('/some/resource') 
//   /some/resource --> HTTP 400
    .then(function(response)
    {
        console.log('success');
        //IMPORTANT -- return to chain data
        return response;
    })
    .catch(function(reason)
    {
        console.log('error');
        //IMPORTANT -- throw to chain rejections
        throw reason;
    })

When a catch handler omits a throw statement, the function returns undefined which converts the rejection to a promise that resolves undefined.

Look in your code for a http interceptor that is following the same erroneous pattern.

The rule in functional programming is always return (or throw) something.

3 Comments

This is the first time I've seen the throw keyword in use with promises. Do you have any example demonstrating the correct behaviour?
I just tested it in a fiddle - works as described, however it still propagates the error to the browser, hence I would rather prefer return $q.reject(reason) over throw reason (see Angular $http docs).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.