What are async iterators and for await...of?
Async iterators yield a sequence of values that arrive over time.
Symbol.asyncIterator — its next() returns a Promise of { value, done }.
for await...of — loops over them, awaiting each value.
Perfect for streaming data and paginated APIs — handle each chunk as it arrives.
// Async generator (simplest async iterable)
async function* fetchPages(url) {
let page = 1;
while (true) {
const res = await fetch(`${url}?page=${page}`);
const data = await res.json();
if (data.items.length === 0) return;
yield data.items;
page++;
}
}
// Consume with for await...of
async function getAllProducts() {
const all = [];
for await (const items of fetchPages('/api/products')) {
all.push(...items);
}
return all;
}
// 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));
return current <= last
? { value: current++, done: false }
: { done: true };
}
};
}
};
for await (const n of asyncRange) console.log(n); // 1,2,3,4,5async function* creates an async generator. yield produces values asynchronously. for await...of consumes each value, waiting for each Promise to resolve. fetchPages yields pages until the API returns empty items. Symbol.asyncIterator creates custom async iterables.
The paginated API example is the most practical use case. async function* is the easiest way to create async iterables. for await...of is the consumer syntax. Regular for...of does NOT work with async iterables.