Transcript from the "Async Functions" Lesson
>> Kyle Simpson: The next feature that we want to look at, one of the most highly anticipated features that people got very, very excited about. As a matter of fact, this feature was already excited more than two years before it landed officially in the spec. People were citing and using this feature as if it was already there, because of that level of excitement, and that is the async function, and also the await syntax inside of it.
[00:00:27] So to give you a quick glimpse into why we might need async functions, and the await keyword inside of them. Let's look at another feature that landed in ES6, which was promises. Promises are a way of representing a future value in a time-independent way. And so you can specify chains of asynchronous steps, much like this.
[00:00:49] I could call fetchCurrentUser, and then I could call .then on the returned promise. And when fetchCurrentUser finishes, it would invoke the onUser and provide me the user that was fetched. And then I could fetch both their archived orders and their current orders, and wait for all of those to come back, and then move on to the next step, where I then say print out the user orders.
[00:01:16] This is what's called promise chaining, and for a good year or two was the pretty much accepted standard for the new way of doing asynchronous programming, instead of what we refer to as the nested callback hell. We can organize things into these vertical chains of promises. And I'll admit that, actually, for a number of years, long before promises even landed officially in ES6, for a number of years I was very excited about this syntax compared to its capabilities, its equivalent in callbacks.
[00:01:49] This is a much nicer syntax, or at least it seemed that way. But I'll tell you that as things stand now, I no longer think that we should be writing promise chains like this. Not that we shouldn't use promises, they're great, but I don't think that we should do .then chains over and over and over again.
[00:02:06] So, I now consider this to be somewhat of anti-pattern, and what replaces it is the async-sync pattern that we get from async functions. So let's start first, before we understand async functions, let's start with generators. We talked a bit ago about generators. Another way of thinking about what a generator can do is that, because there's an iterator protocol attached to it, it can pause itself by virtue of the yield keyword.
[00:02:36] So line two says, fetch the current user, and yield out the result of that, which is a promise. And then wait for that to come back. And that's why I'm then able to say, user =, because that whole statement pauses until we get a user bank. The way it does the pausing is actually that runner.
[00:03:02] I'm using a library utility, and there are dozens of them out there. You may have heard of libraries like Co, or Koa, or Q, or Bluebird, or other sorts of promise utility libraries. They all have a utility on them which is able to run generators as if they're this sort of asynchronous/synchronous tradeoff pattern.
[00:03:27] Which means that if you yield out a promise, it will wait for it to resolve before resuming your generator, and give you the value back. So this syntax is much more straightforward. It's a very almost synchronous-looking syntax. I'm saying user = yield fetchCurrentUser. And then I'm saying archivedOrders, currentOrders = the fetched archivedOrders and the fetched currentOrders.
[00:03:53] And I'll just yield until those asynchronous operations have finished. This is what we call the sync-async pattern. And we could do this starting with ES6 because we had promises, and we had generators. And so, many people started moving from promise chains to this sync-async pattern. The unfortunate part, of course, was that you had to have a runner that could manage that whole pause and resume thing with the iterator for you.
[00:04:23] And so almost this soon as ES6 was landing with promises and generators, people were saying, hey, can you give me syntactic support for doing that whole pause and resume thing without needing a library runner? And that is exactly what the async function does. The async function, now we use an await keyword, instead of a yield keyword.
[00:04:48] It does the same thing, which is that it locally pauses while that promise finishes resolving. And once it finishes, it gives us the value back. So inside of async functions, all I have to do is await on a promise, and then get the value back. And I have a very synchronous-looking style with assignments, instead of having to have this nested promise chaining kind of style of programming.
[00:05:42] And so this is a style of asynchronous programming that many people are comfortable with, and that want to be able to write, and now we have first-class syntactic support for it. This shipped, by the way, the async await functions shipped in ES 2017. So they are in almost every browser that you're likely to be using these days.
[00:06:03] And in fact, they were in browsers quite a bit earlier than that. It's just it officially shipped in the spec in early 2017.