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.