Check out myAngular article series with live demos and Facebook group Angular - Advanced Topics

Angular promises – then vs success

Torgeir "Tor" Helgevold
- JavaScript Developer and Blogger
Published: Wed Aug 05 2015

The Angular team has just announced that the convenience wrappers success and error for promise handling have been deprecated. This is not surprising as the success/error API is not only non standard, but might also lead to unexpected results. In this post I will highlight some of the potential pitfalls from using success.

One of the major advantages of promises is the ability to flatten and chain potentially complex sequences of ajax calls. Not only does this help us simplify code, but more importantly, it helps us manage timing and dependencies through a sequence of calls.

So how does success fall short here?

Simple calls with no chaining is usually no problem, but if you try to chain off a success handler you might be in for a surprise. The fundamental difference between 'success' and 'then' is that success will return the original promise instead of returning a new derived promise. Each then() invocation returns a fresh promise – which is key to chaining multiple promise calls.

It's not that success doesn't allow chaining – it does, but a side effect of returning the original promise is that all chained success handlers will fire during the same cycle. This means that if you return a promise from a success handler, the next success handler will fire before the newly returned promise resolves.

Below is an example of two service calls where the second call is not picked up by the second success handlers since both success handlers are tied to the initial promise.

$http.get('/firstUrl') .success(function(response){ console.log(response); //This promise is returned in vain - no one cares about the result :-( return $http.get('/secondUrl') }) .success(function(response){ console.log('I only have access to the data from the first call'); console.log(response); })

If we were to rewrite this using then handlers instead – we would get the following:

$http.get('/first/Url') .then(function(response){ console.log('first then'); console.log(response.data); //Someone actually cares about the result now :-) return $http.get('/secondUrl'); }) .then(function(response){ console.log('I am enjoying the results from the second call'); console.log(response.data); });

The key difference here is that each then call will wait for the current promise to resolve before executing.

Obviously it's possible to rewrite the success handler example to get access to the second call, but the code is far from pretty.

See below:

$http.get('/firstUrl') .success(function(response){ console.log('first success'); console.log(response); return $http.get('/secondUrl').success(function(res){ console.log('nested handler'); console.log(res); }); }) .success(function(response){ console.log('Fires before the nested success handler. Still only sees the first result though'); console.log(response); })

This is actually pretty ugly and probably negates all the benefits of flattening promise chains. In fact, this is only slightly better than skipping promises altogether and going with straight callbacks.

I am not sure why success was added to begin with, but I guess it adds a slight convenience by flattening the response object by getting rid of the .data property on the original response object. However, we can easily take care of this using then handlers by chaining on an extra then handler like so:

$http.get('/someUrl') .then(function(response){ return response.data;//this flattens the response by removing .data }) .then(function(response){ console.log(response);//same as response.data from above });

If you liked this article, share it with your friends on social media:

We also have a new Facebook group about advanced Angular topics.

I invite you to follow me on twitter