Rethinking Asynchronous JavaScript

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

Preview
Close

Transcript from the "Exercise 5 Solution" Lesson

[00:00:00]
>> [MUSIC]

[00:00:03]
>> Kyle Simpson: So I'm going to open exercise 5 and then I'm going to split my view.
>> Kyle Simpson: And I'm going to open exercise 3 fixed on the side so that we can compare these two, actually do that reverse. So we're going to try to do a side by side comparison of what we were how we were solving Promises with how we're gonna solve it with asynquence because the purpose of the exercise that is to show you the similarities and show off a little bit of how asynquence can improve.

[00:00:45]
Okay, so first of all we have the getFile function. And on the left you can see that we're creating a Promise. So on the right we want to do something very similar but a single step sequence is the same thing as a Promise, roughly conceptually the same thing.

[00:01:04]
So to create a single step asynquence, we're gonna make call ASQ, the function ASQ, which receives a callback that we need to call so that's much like the resolve callback that we're getting over here. Let me zoom out just slightly so it's a little easier to see more at a time, okay?

[00:01:29]
And we're still going to call the fake Ajax call. With the file URL in we're gonna pass in done instead of resolve. So that's all we have to do to make a single step asynquence call, in the most traditional way possible. And you'll notice that it's basically the same thing as the Promise except it's a little shorter and simpler.

[00:01:54]
We're not calling the new keyword. We don't have some more complicated set of resolve and reject that we're having to keep track of, we just have the single callback for done. There are ways to signal errors, but you don't have a separate callback for that. So well get too far into that, but I do just want to quickly show you that the value of having a library is that there are additional benefits that we can get so one of those benefits is that it's such a common pattern to need to wrap like to create these wrapped utilities.

[00:02:28]
Basically it's called lifting taking a function that only receives callbacks and turning that into a function that will return us asynquence or return as a Promise. So another way of doing that same thing would have been to to make myself a getFile. And calling an ASQ.wrap utility that exists in the library.

[00:02:55]
Its job is to take a callback expecting function and make it into a Promise expecting or Promise returning function. So if we pass in fakeAjax to it. Now by default the assumption here is that it treats callbacks as error first style, because that's extremely common in the node world.

[00:03:15]
In our particular case fakeAjax is not error for style. So we don't wanna make that assumption. But in the most majority case you're gonna be dealing with error first tile functions all over node or other Angular libraries or whatever in which case, you just call wrap and that's it.

[00:03:34]
And now we have a getFile function, I didn't need to do anything else. I now have the getFile function that will return us in asynquence and that's done. You can configure this wrap to do other things, and in this case, we're going to tell it that we want to do a simplecb style wrapping because we're assuming that the fakeAjax function that we're dealing with is a simple callback rather than error first style so.

[00:04:00]
Documentation on how you can configure wrap a little bit. Most of the time you won't need to do any configuration at all but it has the option of changing that wrapping behavior you need but that one line there on line 22 that's all I need to do to create my wrapped getFile function.

[00:04:16]
And I can call getFile exactly the same way as I would expect to be able to call it so. I just wanted to show off that there are what there are some of those sorts of benefits from from asynchronous libraries they can add these utilities on, on top of the normal course stuff and help make some of these tasks that we do, these remedial tasks a little bit more straight forward.

[00:04:38]
Okay, so we'll just stick with the easier to understand one but you can know that there are things like wrapping. All right, what about requesting the files at once? Well I'm gonna call mine s1 cuz it's a sequence instead of p1 but is still fundamentally gonna be a getFile call with file1.

[00:04:55]
And s2 is getFile("file2") and s3 is getFile("file3"), okay? All right, so that's pretty straightforward. Let's go to the chain and look at the difference in the in the way the chains gonna work. We have an s1 that represents the first step in our chains us going to the same thing as p1.

[00:05:26]
Now in the asynquence API, rather than calling a .then whenever we want to do some asynchronous step. If we have asynchronous step, which is what output is, we use .val. So I'm going to call .val, and pass an output.
>> Kyle Simpson: Remember this is to get away from the polymorphism that can make APIs harder to learn instead, you just learn each step, and it's clear that val is a synchronous step, as opposed to an asynchronous step.

[00:05:58]
All right, so the next one, I need to to link in the p2 step, right? Now, remember, I told you that we have .seq for receiving sequences. So we could do .seq and return s2.
>> Kyle Simpson: Looks very similar to the way that we do with Promise chain. One of the advantages of having a Promise library to give you extra abstractions to remove some of these paper cuts and other pointless overheads.

[00:06:32]
Asynquence allows you to just pass s2 directly. I'd love to have that with the Promise chains. We don't have that but with a sequence we can just pass s2 directly and so then we do .val(output). Then we do .seq(s3). Then we do .val(output). Then we do .val, output("Ccomplete!"), okay?

[00:07:04]
>> Kyle Simpson: In addition to making that observation, if I know that I can pass these sequences directly into those steps, what that actually means is I don't even need to store these in separate variables. I can literally take the getFile call, replace s1. I can take this getFile call and put it right in place of s2.

[00:07:25]
And I can call this getFile call and put it right in place of s3.
>> Kyle Simpson: Get rid of those entirely. It's still making all three getFile calls. The one on line 29, one on line 31, and the one on line 33, it's still making those all upfront, all at once cuz they're still function calls.

[00:07:46]
But those return values are immediately piped into a chain, and the chain knows how to handle that and sequence it into the proper order. So I don't even have to store them in separate variables and make a function to return them, so I just have it straightforward. So this is trying to illustrate one of the points that I'm making, is that the value of a Promise library, whether you like mine or not, I have no stake in whether you like this particular one, but there's a bunch of great ones out there.

[00:08:10]
The purpose of Promise libraries is to make it easier to work with Promises, and I hope that you can see that what we did on the right hand side Is quite a bit easier than what we had to do the same equivalent on the left-hand side. That's the virtue of trying to use Promise abstractions, is that they have the freedom to get rid of some of the ugly bits, the rough edges, the weird corner case.

[00:08:30]
They have the ability to kind of pave over some of those things, and that's part of the design philosophy behind asynquence, okay?
>> Speaker 2: I used then instead of sequence, what's the difference?
>> Kyle Simpson: The .then function will call it the function that it receives and if it receives a function.

[00:08:51]
It will call the function that it receives and pass it a done call back. The .then keyword for legacy reasons is polymorphic in the sense that if you use it incorrectly and pass it a sequence, it will not choke at you. But the proper idiomatic usage is to call the proper step for the proper thing.

[00:09:15]
So the purpose of the .then step is when you want to get the done function as a continuation and you can use that continuation however you need. The purpose of the sequence step is that you are going to make your own sequence and return it into the chain.

[00:09:30]
That makes sense? And with five or ten minutes of practice with my API you'll get the sense of, I use this step for that purpose this step for that purpose. That's the goal.

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