Course contentsShow
← Node.js
Lesson 202 of 1,9803. Asynchronous Patterns and Flow ControlFree lesson

Asynchronous Generators

You will create data-producing streams that yield values asynchronously to consumer loops.

Mastering Asynchronous Generators

In this lesson, you will learn how to create data-producing streams that yield values over time using async generators.

Up until now, you have worked with functions that return a single promise that eventually resolves to a value. But what if you want to produce a sequence of values, where each value might take time to arrive—like reading lines from a massive log file or waiting for incoming messages from a network socket?

An asynchronous generator is a special type of function that allows you to yield values one by one, pausing execution until the consumer is ready for the next one. It combines the "pause-and-resume" power of generators with the non-blocking nature of promises.

Creating a Stream of Data

To create an async generator, you prefix the function keyword with async and use the function* syntax. Inside, you use await for your asynchronous tasks and yield to push data to the consumer.

async function* getNumbers() {
  for (let i = 1; i <= 3; i++) {
    // Simulate an async operation, like a database fetch
    await new Promise(resolve => setTimeout(resolve, 1000));
    yield i; // Emit the value
  }
}

Consuming the Stream

Because the generator is asynchronous, you cannot use a standard for...of loop. Instead, you use the for await...of loop. This syntax tells Node.js to wait for each yielded promise to resolve before moving to the next iteration of the loop.

async function run() {
  for await (const number of getNumbers()) {
    console.log(number); // Prints 1, then 2, then 3 (each 1 second apart)
  }
}

run();

The beauty of this pattern is its "pull-based" nature. The generator doesn't blast data at the consumer; it waits. The for await...of loop effectively acts as a back-pressure mechanism, ensuring the consumer only receives data when it is ready to handle it. This makes it perfect for managing memory when dealing with large, asynchronous data flows that would otherwise overwhelm your system if loaded all at once.

Key Takeaway: Asynchronous generators allow you to produce a sequence of values over time, letting you process streams of data efficiently using the for await...of loop.