Hiprup

What are async iterators and for await...of?

Async iterators produce a sequence of values that arrive over time, asynchronously.

  • Symbol.asyncIterator — its next() returns a Promise of { value, done }.

  • for await...of — loops over async iterables, awaiting each value.

Ideal for streams and paginated APIs — process each chunk as it arrives instead of waiting for everything.

// Async generator (simplest way to create async iterables)
async function* fetchPages(url) {
  let page = 1;
  let hasMore = true;
  while (hasMore) {
    const res = await fetch(`${url}?page=${page}`);
    const data = await res.json();
    yield data.items;  // Yield each page's items
    hasMore = data.hasMore;
    page++;
  }
}

// Consume with for await...of
async function getAllItems() {
  const allItems = [];
  for await (const items of fetchPages('/api/products')) {
    allItems.push(...items);
    console.log(`Loaded page, total: ${allItems.length}`);
  }
  return allItems;
}

// Custom async iterable
const asyncRange = {
  from: 1,
  to: 5,
  [Symbol.asyncIterator]() {
    let current = this.from;
    const last = this.to;
    return {
      async next() {
        await new Promise(r => setTimeout(r, 100)); // Simulate delay
        return current <= last
          ? { value: current++, done: false }
          : { done: true };
      }
    };
  }
};

for await (const n of asyncRange) console.log(n); // 1,2,3,4,5 (with delays)

async function* creates an async generator that yields values asynchronously. for await...of consumes each yielded value, waiting for the Promise to resolve. fetchPages fetches pages until hasMore is false — the consumer gets each page's items as they load. Symbol.asyncIterator creates custom async iterables.

Show the paginated API example — it is the most practical use case. async function* is the easiest way to create async iterables. for await...of is the consumer syntax. Know that regular for...of does not work with async iterables.

What are async iterators and for await...of? | Hiprup