Async Generators, the superior async await

An async generator is a special way for computers to do things that take time, such as getting information from the internet. Lets take a deeper dive into it from a real world example.

Imagine you're at a magical bakery, and you're trying to bake a variety of delicious cakes. You have a helper named Alice, who is a bit of a baking expert. Now, baking takes time, and some steps might require waiting – like waiting for the cake to bake in the oven. This is similar to how computers sometimes need to wait for things to happen, like fetching data from the internet.

Now, in the world of programming, JavaScript is like your magical kitchen. Async generators are like a special recipe book that Alice follows to bake cakes, but with a twist. You see, Alice can't bake all the cakes at once – that would be too overwhelming. Instead, she bakes them one by one, taking breaks when needed.

Here's how async generators work in the magical bakery of JavaScript:

  1. The Recipe Book (Async Generator Function): Just like a recipe book tells Alice how to bake cakes, an async generator function is a set of instructions for JavaScript on how to do tasks that might take time, like fetching data from the internet or reading a big file. This function is special because it can "pause" and "resume" whenever it needs to wait for something to happen.
  2. Baking Cakes (Generating Values): Instead of baking cakes, the async generator function produces values over time. These values are like the cakes that Alice bakes. But instead of baking all the cakes at once, the async generator bakes one "value" at a time, and then takes a break before baking the next one.
  3. Taking Breaks (Pausing and Resuming): Imagine Alice is baking a cake, but then realizes she needs more chocolate chips. She pauses, goes to get the chips, and then resumes baking. Similarly, the async generator can "pause" its execution when it needs to wait for something. It tells JavaScript, "Hey, I'm waiting for something, let me know when it's ready!" Then, when it's time, it "resumes" where it left off.
  4. Enjoying Cakes (Consuming Values): Now, you can be the one enjoying the cakes Alice bakes. In JavaScript, you can "consume" the values the async generator produces. It's like waiting for Alice to finish baking a cake and then getting to eat it.
  5. Many Cakes, One by One (Async Iteration): Just as Alice can bake multiple cakes, the async generator can produce multiple values over time. And just like you'd eat the cakes one by one, JavaScript can "consume" these values in the order they're baked.

So, why are async generators useful? Imagine you're creating a website that shows cute animal pictures from around the world. You need to fetch these pictures from different websites, which can take time. With async generators, your JavaScript code can fetch and show these pictures one by one, without freezing up the whole website. This way, your website stays responsive and enjoyable, even when dealing with slow tasks like fetching data.

In simple words, async generators help JavaScript handle tasks that might take time, like baking cakes one by one, so your programs stay smooth and your users keep enjoying their experience. Just like Alice's magical bakery makes sure you enjoy cakes without waiting too long, async generators in JavaScript keep things running smoothly even when there's waiting involved.

Lets dive into some code now -

// Imagine we have a function that simulates getting data from the internet
function fetchDataFromInternet(delay, data) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(data);
    }, delay);
  });
}

// Async generator function that fetches data one by one
async function* fetchMultipleData() {
  yield fetchDataFromInternet(2000, "First piece of data");
  yield fetchDataFromInternet(3000, "Second piece of data");
  yield fetchDataFromInternet(1500, "Third piece of data");
}

// Using the async generator
(async () => {
  for await (const data of fetchMultipleData()) {
    console.log("Received:", data);
  }
  console.log("All data received!");
})();

In this example:

  1. fetchDataFromInternet is a simulated function that returns a promise, pretending to fetch data from the internet. It takes a delay parameter to simulate the time it takes to get the data.
  2. fetchMultipleData is the async generator function. It uses the yield keyword to produce values one by one. Each yield represents fetching data from the internet with a different delay.
  3. The for await...of loop is used to consume the values produced by the async generator. It waits for each value and logs it.
  4. When you run the code, you'll notice that each piece of data takes a different amount of time to be received, but the loop doesn't wait for all of them to finish before processing the next one. This demonstrates the asynchronous nature of the generator.
  5. Finally, the "All data received!" message is logged when all the data pieces have been fetched and processed.

Remember, async generators are especially helpful when dealing with tasks that have varying time delays, like fetching data from the internet, reading large files, or processing data in batches. They allow you to handle these tasks efficiently and without freezing up your program.