Promises, Promises Pt. 4
Angular Syntax: Gettin' Dirty
Okay, this’ll be quick. This article is just for those using Angular, especially those versions before Angular 2. I figure that even if the entire world stopped writing new apps in Angular, there would still be a metric pantload of legacy apps to maintain. This article assumes enough familiarity with Angular to create controllers and services. The reason I’m writing this article is that Angular has one particular quirk about timing: dirty-checking. You can’t just change data; you gotta tell Angular you did it so that it can go through the laborious task of updating the view.
Fortunately, this is fairly simple. Angular has documentation for $q, their take on Kris Kowal’s Q. When promises from Angular resolve or reject, they trigger the scope to refresh, which updates the view.
$q
Let’s start with the $q library. It’s very easy to bring in, since it’s part of the default “ng” module. You can either use $q.resolve
or $q.reject
to create a promise from a value or an error. $q.resolve
is an alias for $q.when
to match ES6 naming standards.
There is also another method of creating promises: creating a deferred with $q.defer()
. The idea of a deferred is that it’s like a promise that you can change programmatically. Then you release a promise from the function. The deferred is hidden within the scope, but its external promise becomes an indicator of it.
And $q
can be used the same as the Promise
constructor, which is good if you want your code to be easily refactored later. One thing I have noticed often in my JavaScript career is that I’ll depend on a library that fills a gap in the code (such as jQuery, Underscore, or Flash), and then the native APIs will catch up or there’ll be a superior framework, rendering that library obsolete. Writing code that comports with the coming standards is a good way to ensure that switching your code over later will be easier.
And speaking of the ES6 standard, $q.all()
and $q.race()
perform the same functions described in the last post.
$http
This is really where my experience with promises in Angular started. $http
(click here for the docs) encapsulates making http requests like $.ajax
in jQuery. In fact, let’s do the basic run-through of how to get stuff from a web API to the controller.
The Group Service abstracts away the interaction with the web API, and the Main Controller just consumes promises from the service and updates the view based on that. When it comes to 80% of apps in production, you’re going to be doing a lot of this. But there’s another way of making promises that does a great job of helping you prototype and get quick feedback to see if what you’re building works.
$timeout
In some of the examples above, I created the “lucky promise” using $q
and setTimeout
. $timeout
does a great job of making that code quicker.
If the code throws an exception, the promise rejects; if the code returns a value, the promise resolves with that value. Now, this is a very contrived example. Where would you actually use this functionality?
There are lots of scenarios that call for $timeout
, but the one that I faced the most was just demonstrating that my UI behaved as expected. I always liked coding from the UI backwards; that way I had an easier time getting feedback from clients, and an easier time verifying that what I was doing would work in the first place. After all, user interaction is not a static thing. It takes place in the physical space of the view, but also in time. By using a timeout of about 2 seconds, I was often able to show the UI that I had planned in a way that made sense to non-technical people or end users. Let’s say that I’m making a cloud-based todo app, and the first thing that happens after the end user signs in is that it loads whatever tasks that that user has for the day. Well, a good way to fake that is to create a couple of dummy tasks and return them from a 2 second timeout.
And here’s a simple template for this data
Okay, so let’s say that you’ve put this in front of a client or a manager or a somebody and they like it, and they want you to move forward. Well, you know that eventually you’ll end up putting that promise in an external service that will call a web API, but the guy that makes the web API isn’t around, or maybe he’s just not there yet, and you have work to do. So let’s at least move that crazy logic out of the controller.
So, now your controller logic is cleaned up, the API interaction abstracted away. Sure, your service layer is still a thin tissue of lies, but as soon as the API guy gets his act together, it’s an easy switch out.
You can see how easy it is to pretend that you have the right functionality. You are now free to test your interaction layer without needing to have the whole thing figured from top to bottom.
I’ve covered how you can use $q
, $http
, and $timeout
in Angular to build and test asynchronous interactions. In the next post, I’m going to run through a few real-world scenarios I’ve faced that required constructing complex promises.