Promises, Promises Pt. 2
Creating and Listening in ES6
In a previous post, I introduced the idea of promises and the purpose they serve, while also delivering an ode to nachos, a paean on a pan, as it were. This time, I actually want to get to the nitty gritty, and demonstrate how to create, transform, and combine promises in the new ES6 syntax. I’ll follow up with the same article in the syntax more common to Angular.JS, since that’s where most of my work has been.
So, let’s make a simple promise, one that resolves with the numeric value three. What does that look like?
So now we have a promise that resolves with the value 3. This is very exciting. What about rejecting? Can we reject with an error?
Welp, that was fun, I guess. How about this: can we create a promise that takes a random int from 0 to 3, and if it’s equal to 0, reject, and if not, return the val? Well, that’s pretty easy. The Promise constructor just needs a function that will take a
reject function as parameters, then act accordingly.
Because the truth is that stuff happens. The reason that the promises have rejected states is that sometimes stuff goes wrong, and you have to adjust. Here’s another way to get the exact same effect:
All right, but one of the big points that I mentioned was asynchrony, and so far, these promises have all been on the same process. Let’s use setTimeout, and rewrite the last promise so that it will do all this process after two seconds.
You’ll notice that I switched out of the “throw an error” model above. It’s better to be clearer, I suppose. But I really like that syntax, and I think I want to keep it, so I’m going to write a utility function.
I want to make a function that I’ll call delayer, which will take in a function and a delay in milliseconds, then return a new promise. That promise should:
- Wait the specified delay, then evaluate the function.
- If the function throws an error, the promise should reject with the error.
- If it returns a value successfully, it should resolve with that value.
And boom! We have written a utility function to return promises! As you can imagine, you could write utility functions like this to do all sorts of things, such as:
- Create a Vanilla.js, cross-platform AJAX library!
- Access LocalStorage or cookies asynchronously
This is very low-level, of course, but what about jQuery? After all, jQuery is by far the most commonly used library if you want to make something quick with a little AJAX, which is ground zero for promises. You’ll be glad to know that jQuery.ajax returns a jqXHR, which can be treated like a promise.
There may be a tiny bit of difference betweent jQuery promises and the new official versions of promises, so if jQuery promises don’t act like you expected, there’s something to put on your suspect list.
Well, now we’ve created them, how do we respond?
Listening to Promises
We’ve got these strange little objects that are creating these events with values. How do we listen to them? How do we actually do something with those values? Well, that’s where the
catch functions come in.
then function takes in up to two functions as arguments: the success callback, and maybe the failure callback. The
catch function only allows you to attach a failure callback. You can do whatever combination you want, but in a production setting, for most Promise specifications, there’s a good chance that you should be preparing for errors as well as success. You don’t want to annoy your users. Let’s take a look:
One super-important thing to know about
catch is this: if you attach them after the promise resolves or rejects, they will still fire! That’s right! With most situations regarding events, if you attach an event handler after the event fires, you’ve “shut the barn door after the horse has already run off.” You won’t catch the event that’s already gone. With promises, you can take a resolved or rejected promise and capture its value as many times as you want. Isn’t that fantastic?! You don’t have to check its state first. In fact, come to think of it, I’ve been coding with all sorts of promises for a few years now in about 4 different frameworks, and I’m pretty sure that I have never checked whether a promise is finished or not. How cool is that?
All right, we’ve created promises, and we’ve responded to promises. Everything we’ve done is asynchronous, but still very imperative; that is, we’re making the request and responding to it. But one of the strengths of promises is that we can use a few tools to transform them and combine them in a way that’s more like functional programming, and that’s what we’ll get up to in the next post.