Rethinking Asynchronous JavaScript

Exercise 7 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 7 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 7.


Transcript from the "Exercise 7 Solution" Lesson

>> [MUSIC]

>> Kyle: Let's talk about how to use a generator to solve our running example of parallel files ASAP rendering. First thing this get file function is currently given to you with an ASQ returning capability. Exactly the same thing could happen if you return a Promise. So there's no reason you have to do asynquence, sequences, here.

Because the runner that I've provided you is capable of understanding Promises equally well with sequences. I just started out there because that's the place that we were at the end of the other exercise. But there is no requirement that this is a sequence only. [COUGH] Okay, so we're gonna do ASQ().runner.

Remember I gotta put this parentheses on here. You have to start a sequence cuz this is a method of a sequence rather than a static function. And I'm gonna pass it
>> Kyle: A generator which I'll call main for now.
>> Kyle: That's my basic set up. If you ended up after this class never using asynquence again and you went and you used the co utility guess what you're gonna do.

You gonna replace that part with co and if you ended up using the Q library you're gonna replace that part with Q.spawn, okay? So every one of them has the same utility on it. All the stuff that I'm teaching you here is not asynquence specific. All right, now inside of our utility, we need to call the getFile function and when it responds to us then we need to print it out.

So we could say, text1 = yield getFile("file1"); and then output(text1);. And then we could say text2 = yield getFile("file2"); and output(text2);. And then text3 = yield getFile("file3"); and output(text3), and then output("Complete!"), okay? We could do that. Does everybody, before we answer whether or not this is fully correct or the right way, does everybody see how that would work?

We're going to wait for text1 to get assigned until after this request finishes. So that's what the yield keyword is giving us here. We're yielding on this Ajax call. This is a Promise, so we're yielding out the Promise the runner in asynquence knows what to do with that Promise of that sequence and it waits resumes and gives us the data back, okay?

But now, does anybody spot a problem with this?
>> Speaker 2: It's not a request if it-
>> Kyle: Exactly, see we're not even calling this one until after this one finishes have violates our in parallel principle right. So, if you want to do sequentiality in generators, it's pretty easy. You just put a function call after a yield, and it's going to be sequential.

But if you wanna do things in parallel, you have to be ever so slightly more clever. So here's what we're gonna do. I'm going to take that getFile call and move it up here.
>> Kyle: And I'm gonna take that call. And I'm going to move it here. And you'll notice that I'm not putting the yield keyword in those calls, that's on purpose.

So now, if I requested all three of them in parallel, does everybody see that, exactly the same as it's been all day long, okay? Well now that I've got those getFile calls, I don't need those anymore. So what am I gonna replace them with? I'm gonna replace them with the Promise, all right?

>> Kyle: So now we have request in parallel sequencing their output.
>> Kyle: Does everybody see how I did that? Cuz the promises, what do they do? What is their most fundamental thing, even thumps, what do they do? They eliminate the time state. So it doesn't matter when when these are going to relatively finish, we're going to sequence their responses based upon how we write the yield code.

>> Speaker 3: Instead of assigning the yield p1 to text1, could you just say output-
>> Kyle: I'm about to get there. I'm just asking to make sure everybody understands this part, okay? Is there anybody that having trouble understanding this part? All right, so now exactly as you just said, I'm assigning this to a variable and then immediately printing the variable.

Why do I need the variable. Why not just take this yield p1 and put it right there and take that line out. And take this yield p2 and put it right there and take those lines out. And take this yield p3 and put it right there and take those lines out.

>> Kyle: How cool is that? Compare that to what we've progressively been building from where we started the beginning of this workshop with all that ridiculous callback nightmare. Then thunks in Promises, in map and reduce, in asynquence. We got better and better and better. But how many of you feel like we've arrived at something a whole lot better than where we started, right?

No new functionality whatsoever. Just an entirely different and better way of expressing the same code, why does that matter? Because our code is a form of communication. We need to communicate not only with our other team members but with our future selves of what the code supposed to do.

This is more expressive. It's more understandable, it's more readable, it's more learnable. Given the ability to write code like that I cannot understand how I spent so many years writing all that other crap.
>> Kyle: I wish I could go back and fix all those other bad pieces of code that I wrote.

Any questions about exercise seven? There's no other magic here. I'm going to challenge you to go back and reread through the slides, and retry the exercises. But it really is as simple as it looks right there. It really is as simple as asking myself, do I need something to happen in parallel?

If so, store those things into intermediate Promises and then sequence their responses. Do I need to have them happen sequentially? Make sure they show up after yield keywords, that's it. And if you need higher levels of abstraction like some of those abstractions we talked about with all or other things like that.

Guess what you have access to all that stuff these are just Promises. So you can use promise.all and promise.raise in any of those other abstractions as necessary because they all just produce promises. So you could do a yield promised.all. If you needed to wait on all three to finish before moving on to the next step, just yield promised.all.

If you need to only listen for one or three to finish and you don't care which one happens first, yield promised.raise. Or any of the other dozens of abstractions that are out there. That's another benefit of weaving Promises into the generator patterns, that we have access to all those obstructions if we need it.

>> Kyle: Any level of complexity that you have in asynchronous programming can be woven into the style.
>> Kyle: But you're not going to get there unless you practice this, so I'm going to challenge you don't let this be the last time you look at it, you walk away and you like, that's cool but I'm still gonna do all the old stuff.

It's time to up our game. It's time to practice and try to get our brains wrap around this new style. I promise you, your team members and your future self are gonna thank you the more effort you put in making your code more reasonable. Okay, any more questions about generators and Promises.

How are we feeling so far feeling like your brains are starting get a little bit mush. Okay, see a few in both directions. Yeah you might need a little bit more caffeine that's cool, got it. We're gonna take a break. So go get yourself a recharge of your caffeine your monster drink or whatever.

>> Speaker 2: [LAUGH]
>> Kyle: Because when we come back we're going to take the red pill and go even further down the rabbit hole.

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