Rethinking Asynchronous JavaScript

Exercise 3 Solution

Kyle Simpson

Kyle Simpson

You Don't Know JS
Rethinking Asynchronous JavaScript

Check out a free preview of the full Rethinking Asynchronous JavaScript course

The "Exercise 3 Solution" Lesson is part of the full, Rethinking Asynchronous JavaScript course featured in this preview video. Here's what you'd learn in this lesson:

Kyle walks through the solution to exercise 3.


Transcript from the "Exercise 3 Solution" Lesson

>> [MUSIC]

>> Kyle Simpson: So let's talk about this exercise from the perspective of promises, a new tool that we're learning to try to help improve the way we solve the problem. Just as I was mentioning before, our first step is to create the Promise in the getFile function, okay? So we're going to need to return what we create, so new Promise and our Promise function is gonna receive a resolve and a reject.

>> Kyle Simpson: Now we need to make the fakeAjax call right away. So let's make the fakeAjax call with our filename. And what callback do you suppose we should provide to fakeAjax?
>> Kyle Simpson: The resolve functions, pretty straightforward, right? Now here we're not taking care of errors, so actually just to keep things simple, I'm going to just leave off the reject because we don't care about the error case but of course, if our Ajax function had the ability to handle errors, we could wire up that error handling through the reject function.

So fakeAjax file and resolve, pretty straightforward. Any questions about that part?
>> Kyle Simpson: Yes.
>> Speaker 2: In the real life situation, we don't have to create a promise object of whatever we are going to get [INAUDIBLE] should it be called, we're going to give us a promise
>> Kyle Simpson: So the question is, in real life, are we gonna have to make our own promises and the answer is sometimes.

Because sometimes, you're going to call a utility that is already promise aware and gives you a great promise. Sometimes you're gonna call the utility that gives you something that's kinda like a promise, but it isn't really and in the promise world, we call that athenable and then you're gonna need to make a promise that wraps around it.

Sometimes you're going to have a callback utility that's not even remotely promise aware, and you're gonna need to adapt that to a promise, which is what we're doing here. We have a utility that doesn't know about promises and we're adapting it. This pattern is called lifting. We are creating a promise aware utility on top of the fakeAjax function.

And in fact Promise libraries do offer utilities that will do automatic lifting for you. They will create this wrapper pattern that we're doing here and we're doing it manually, so we can illustrate, but we'll see that Promise utilities libraries out there, they do this for us because you don't want to be tripping over doing that adaptation yourself.

That's a repeatable pattern, it belongs in a library. Okay, so we still want to call the getFile function three times. Just like with Thunks, we're gonna get something back in this case they're gonna be promises. I'm gonna say p1 = getFile ("file1") and p2 = getFile("file2") and p3 = getFile("file3").

Great, awesome. So we've made those three calls in parallel. What are we going to do with them? How are we going to sequence their responses? That's the whole point of this exercise, sequencing the responses. So, let's think about sequencing our responses together. We know that p1 is at some point gonna finish.

We're assuming in this system, that the promise always resolves, so at some point, its going to finish. So to respond to that finishing, we can simply say p1.then. Now we know that the success handler from p1 is going to receive the output that we gave it just like up here, our Promise that result functions going to get past the response text and that will then propagate into the Promise chain.

So what we need here is a function that can receive the text and print it out and we have a utility called output. So we could do it like that but it turns out even easier since we have a utility that already has that call signature, we can just simply pass a reference to the output function.

Not calling it, don't put the parenthesis in there. You wanna pass a reference to that function into the chain. Here, and now I want to make a really important point about Promise chains from a style and readability perspective. You'll see tons and tons of examples of promises where the way the promise chains are illustrated is to use inline function expressions.

In fact, this is one of the favorite places that people like to pull out ES6 error functions and put them as inline function expressions. I think this is a terrible idea, to put inline function expressions all over your Promise chains. Use function declarations. The point of a Promise chain, if it has any point at all, from a readability perspective, the only readability perspective is that you should be able to easily vertically scan down and understand what the flow control is like we did in that pseudo code.

If your chain is littered with all kinds of inline function expressions and weirdness and stuff like that, you've completely lost all the readability advantages of the Promise chain. So I prefer to use a function when I have one. That doesn't mean you won't ever use a function expression, but I'm gonna say if there's an opportunity to not use an expression and instead do a declaration, it's better to go that way, okay?

All right now, what we've said is whatever Promise one finishes, we wanna output it. We have ensured that the Promise one, that the file one contents are the first thing to be printed. So we've ensured just by way of how this works. We know for a fact that we're going to be printing in order just like with Thunks.

What's the next step? Well your instinct might be to say well I know that the way to change some promises together, is to return one promise from another promise. So it would seem very attractive for us to just pass in Promise two into the chain and make it so that it wires it in and wanes.

And I wish that's how Promises worked. I wish you could pass a Promise in to the then method and have it automatically know what to do. Unfortunately, Promises don't have that feature. So you have to pass in a function that returns that Promise. Again, an example where people use error functions all the time.

Is this a case where I'd make that into a function declaration? Perhaps. But for our purposes, just to keep things clean, I'm going to use the function expressions, but just with the admonition, you want to try to minimize the amount of expressions in your flow control. And if you're gonna have them, by goodness please make them like one liners.

If you have 5, 10, 15, 100 line inline expressions inside of your chains, that's a terrible idea, okay? But we've returned P two from the chain which means that the very next step that happens here is gonna magically be waiting on P two. Does everybody see that? So what do we want to do after P two finishes?

You wanna output again. And then you can probably guess what happens next right. .then function, return p3 and then .then output. And finally .then, just for completeness sake with the other examples, output a complete message.
>> Kyle Simpson: There's our flow control using promises. It's vertically oriented rather than being nested together, certainly has increased the readability factor by a bit.

But that's the least important part of what's happened. We've also introduced all of the sanity and trust that comes from the Promise mechanism. We can trust that if that fakeAjax utility somehow misbehaves or is malicious or is hijacked or whatever, we know that no matter what it does, if it calls that resolve 50,000 times, we're only gonna get notified once because that's the way the Promise system is built.

So we've shifted our trust from some untrustable third party into a very trustable system, in fact, one that's built into the language. But even if it wasn't, we know we can audit and trust the Promise system to do what its supposed to do.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now