JavaScript AsyncIterator

JavaScript AsyncIterator

An AsyncIterator is just like a normal iterator, except every .next() call returns a Promise.


1. The 30-second mental model

Normal IteratorAsyncIterator
Gives the next value synchronouslyGives the next value asynchronously
Works with for…ofWorks with for await…of
.next() returns {value, done}.next() returns Promise<{value, done}>

2. The easiest possible AsyncIterator

An async generator function (async function*) automatically returns an AsyncIterator.

// 1️⃣ create
async function* countSlowly() {
  for (let i = 1; i <= 3; i++) {
    await new Promise(r => setTimeout(r, 500)); // wait half a second
    yield i; // hand out the next number
  }
}

// 2️⃣ use
(async () => {
  for await (const n of countSlowly()) {
    console.log(n);
  }
  console.log('Done!');
})();

Run this in any browser console or Node.js and you’ll see:

1   (after ~0.5 s)
2   (after ~1.0 s)
3   (after ~1.5 s)
Done!

That’s it—no extra classes or libraries.


3. One more practical example: “Fetch tweets”

Imagine we’re receiving a page of tweets at a time from an API.

// fake async fetcher
async function fetchPage(page) {
  await new Promise(r => setTimeout(r, 300)); // network delay
  const tweets = [`tweet #${page * 2 - 1}`, `tweet #${page * 2}`];
  return { tweets, hasMore: page < 3 };
}

// our AsyncIterator
async function* tweetStream() {
  let page = 1;
  while (true) {
    const { tweets, hasMore } = await fetchPage(page++);
    for (const t of tweets) yield t;
    if (!hasMore) break;
  }
}

// consume it
(async () => {
  for await (const tw of tweetStream()) {
    console.log('📢', tw);
  }
})();

Output (with tiny pauses):

📢 tweet #1
📢 tweet #2
📢 tweet #3
📢 tweet #4
📢 tweet #5
📢 tweet #6

4. DIY object that fits for await…of

If you want to build your own AsyncIterator without generators, give it a next() returning a Promise and tag it with Symbol.asyncIterator:

const threeColours = {
  colours: ['red', 'green', 'blue'],
  index: 0,
  async next() {
    if (this.index === this.colours.length) {
      return { value: undefined, done: true };
    }
    await new Promise(r => setTimeout(r, 400)); // pretend delay
    return { value: this.colours[this.index++], done: false };
  },
  [Symbol.asyncIterator]() {
    return this; // make it usable with for await…of
  }
};

(async () => {
  for await (const colour of threeColours) {
    console.log(colour);
  }
})();

5. Quick cheat-sheet

  • Create: async function* myGen() { … }
  • Consume: for await (const x of myGen()) { … }
  • Manual: object with next() → Promise and [Symbol.asyncIterator]()
  • Always works in async functions / modules; top-level await is OK!

JavaScript AsyncIterator async generator for await of promises iterable tutorial examples