JavaScript: The Recent Parts

Async Iteration

Kyle Simpson

Kyle Simpson

You Don't Know JS
JavaScript: The Recent Parts

Check out a free preview of the full JavaScript: The Recent Parts course

The "Async Iteration" Lesson is part of the full, JavaScript: The Recent Parts course featured in this preview video. Here's what you'd learn in this lesson:

Kyle goes into further detail on why await cannot be used in a regular function, and offers up a library that fills the gap in the language.


Transcript from the "Async Iteration" Lesson

>> Kyle Simpson: Now, there are some issues with async functions. And you might've seen, for example, in that exercise that we just did, that if you tried to run a function and pass it to forEach, like I'm doing here. And then, inside of it, you wanted to call the await keyword, you might have noticed that this would fail.

And the reason it fails is because the await keyword has to be used inside of an async function, not inside of a regular function. So what do we do whenever we want to do this sort of deep awaiting, if you will, when we have a function boundary? You might think, okay, well, my solution is, I just need to pass the async function to the forEach method.

Except the problem with that is that async functions come back with promises, and the forEach method does not know what to do with a promise. It does not know how to wait on promises to finish. So you'd get back an iteration over a bunch of promises, but they wouldn't be waiting on each other, and they would not be printing the contents of this file in the correct order.

They would just print them as fast as those three separate promises resolved. So what we're really getting at here is that there's actually a conceptually missing piece to the puzzle. Not just that the syntax isn't what we want, but there's a missing piece to the puzzle. And it is that what we really need is an asynchronous iterator.

We need something like for each, or map, or filter, or reduce. But we need it to be able to pause automatically at each iteration, and wait for a promise before it comes back. And that's not what is built into JavaScript, the .forEach, the .map, the .filter, .reduce, the .flat, now all of those, those are all what we call synchronous iterators, they run eagerly over the values that are currently in the array.

And they don't know that they should pause if they find a promise. So what we need is a lazy asynchronous iterator that can pause whenever it sees, I'm sorry, we need an eager asynchronous iterator, which means it tries to go to a promise. It tries to go to each value, but if it sees a promise, then it moves on, then it waits before it moves on.

That's not built into JavaScript, and as far as I know, there's no proposal that is active to add it to JavaScript. But it is definitely a missing piece. And so, as an illustration of a way to solve that, I have built a library called Fasy. And Fasy provides you with eager asynchronous iterator functions for all of your standard functions, like map, filter, reduce.

It supports transducing, and what we see here, for example, is I can do concurrent map, or I can do serial forEach. So it provides all of these iterators in both their concurrent and serial forms. And that, you can use alongside of the standard built-in eager synchronous iterators that JavaScript already provides.

You notice now that I can pass an async function directly into FA.serial.forEach, because the async function, when it gives a promise, FA.serial.forEach knows what to do with that promise. Whereas the normal built-in forEach would not know what 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