JS.Next: ES6 / ES2015 Promises
This course has been updated! We now recommend you take the ES6: The Right Parts course.
Transcript from the "Promises" Lesson
>> Aaron: Promises, what problems do they solve, why do we need them? So, async code, async code looks messed up, right? It's not always clean. And when you just get done writing this perfect async structure, this is messed up, I shouldn't have done this, there's gotta be a better way.
[00:00:20] Cuz sometimes, especially in jQueryville, you end up with this guy. And who's ever had one of these? You're 18 levels deep, and you're like wait, where did I define name? And it's seven levels up, and your days look really sad. And maybe it helps with your code organization cuz some people are like dude, I do async for breakfast, it's no big deal.
[00:00:41] I have two more for lunch. But your code looks like it's totally jacked, and promises are here to help us kind of,
>> Aaron: Make that stuff cleaner. And an example is something that's dirty, and this is a simple example, but it's like you're trying to load an image, and you just wanna see when it's done.
[00:00:58] You know what I'm saying? All this async stuff, so, I get this image, and you get this loaded function, and if the image is loaded, then just call loaded, but if it's not, add an event listener for loaded and then call loaded. And then I also have to have an error functionality.
[00:01:14] So if you just make the code for something that's fairly simple look really ugly and if this is promise-based, you could just say image.load.vent, or image.ready, or something. And if that ready was a promise, then you could just daisy-chain your .vent there, and be good to go. You wouldn't have to deal with all this stuff, so anyway.
[00:01:41] It helps keep your code clean. So let's talk about the promise constructor, I wanna talk about how you construct. I wanna talk about once you've constructed, you have instances, and then there's some static methods that you use as well. So this is the constructor, it's just new Promise, and you have to give it a function.
[00:02:01] And the function has got two things it's gonna get passed into it, a resolve method and a reject method. Okay, so you can do some code here, some amazing talk to the server, do something async, who cares? But then later on, if everything turned out fine, you call resolve with the stuff that it worked.
[00:02:20] Okay, and if it doesn't turn out well, then you go ahead and reject it. And you say why you rejected it, okay? And this is how you use a promise, okay? And then in your code where you created this promise, you just give this promise back to somebody and that somebody can listen and wait for the events to happen, okay?
[00:02:44] All right, so what are some things you can do that's async? Can anybody think of any? Like something AJAXy, maybe something web sockety, maybe you could load an image. You could read-write to local storage, that's synchronous, but it looks ugly when you get everything done. And you can do a lot of DOM writing, you can show some sort of spinner loading.
[00:03:07] Anyway, but this is the simple As and Bs and Cs of the constructor. Any questions on this? No? Pretty simple, in the success, we kind of use this when we do the callback pattern, we usually make you pass in two callback functions, the success callback handler and error callback handler.
[00:03:33] So this is like that, the resolve is kind of like the success handler, except for I don't have to pass it into your scope. You just tell me which one should I fire, and I can kind of keep the code over in my line if that makes any sense.
[00:03:45] It's gonna execute in my context, which is really nice. So yeah, and the reject is kind of like the error handler. So anyway, so that's the constructor, let's talk about instances. So now we have an instance, a promise can be in one of four states. So it can be fulfilled, which means it was resolved.
[00:04:05] It can be rejected, which means it was rejected. It can be pending, which means whatever it's doing before it calls resolve or reject, that's still happening. It hasn't called either of those yet. Maybe it's waiting for a DOM click, I don't know. And then it can be settled.
[00:04:23] So and settled is more for like terminology only. We just use it, so that we can say it's either rejected or resolved without having to use that many words. So anyway, so let's say someone gives me this promise. I could say promise.then, and this then's not gonna get executed until, if this thing took 20 seconds, my code would just register this then handler.
[00:04:49] And it's not gonna call this until the resolve method is called. So, you just kind of sit there, and it just sits there and waits. For those that aren't familiar with promise, it's a pretty cool syntax. So in then, you could pass in a second function, which is kind of like the error handler.
[00:05:08] So that's the reject handler. So if I made my own GET method, like okay, so I'm gonna do this jQuery get, and when I get back from the server, I'm gonna call resolve and pass it the data. But if I fail, I'm just gonna call reject, right? So this is my jQuery HTTP method, but I've gone and wrapped it in this new promise.
[00:05:32] So I return this promise, and over in my code, sorry, I can just say get('users.all') and then myController.users = users. And if there's an error, I can just state, go ahead and delete myController.users. This is kind of how you would use it, does that make sense? So if the server was super slow, so I call this, and then it gives me back the promise, and then we register this then handler.
[00:06:02] If the server was super slow, and that took a minute, which it shouldn't, but even 100 milliseconds can be a long time. This just kind of sits around, and it's not gonna fire until that thing resolves or rejects, so that's that. You could also catch it in a second handler, in a second .then.
[00:06:20] So if you don't like the two functions in the .then, you could put your reject handler in a .catch. That's the other API on the instance. So we could do this, we could say go ahead and get all the users, go ahead and get all the posts, and then there's this promise is the all, which basically says wait till all of these are done, and then go ahead and do this.
[00:06:49] And if any of them fail, go ahead and do this, if that makes any sense. So there's promises to all, which will allow you to wait for multiple things. And then,
>> Aaron: So yeah, you could do this too, let's say the server didn't give you JSON, it gave you a string.
[00:07:07] So you could say users.get, users.all, or get all. And then you have this string, so you could say go ahead and return the JSON parse of that string. And then you could do it a second .then, and you could say myController.users = users. So basically, when you return something, it's gonna pass whatever you returned into the next .then.
[00:07:36] So see how I did two .thens, whatever I return gets now passed into the second .then. So you can kind of, when you chain them up, you can kind of override what you specify. Yeah?
>> Speaker 2: Well, one question on the chat here, do the ES 6 promises implement the promises A spec or the A plus?
>> Aaron: I think it's A plus.
>> Speaker 2: Okay.
>> Aaron: But yeah, so, I'm not positive. I know that some of the browser vendors are working on making it be more integrated into just the elements, but I'm not sure 100%. So, that was a good question. Even more compact, you could just say get('users.all') and then you could say .then(JSON.parse), which it would call JSON.parse and pass it the users, and then you could say .then.
[00:08:27] And it would actually return it, right, cuz JSON.parse doesn't impose a return. Anyway, so yeah, you could even make it even more compact. So that's the instances of promises, and then you've got these static methods, like promise.all is what, remember what we said, you give it an array of them, and it won't fire the .then until all of them are resolved?
[00:08:52] You've got a promise.race, which is basically saying hey, of all of these, don't call the .then until one of them settles, like just wait for one. You can say promise.reject, and that will just give you a rejected promise. Cuz like if you're in a circumstance, maybe you don't even wanna go to the server and do your async stuff, and you don't wanna just create a promise and reject it for the sake of doing that.
[00:09:18] So the short code for that is promise.reject, and you can just make a rejected promise and return it. And then the opposite of that is maybe there's one time when you don't wanna go to the server, and so you can just do promise.resolve, so.