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.
If we were to rewrite this using then handlers instead – we would get the following:
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.
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: