When values arrive over time — pages of an API, lines of a file, chunks of a stream — async generators and for await…of let you loop over them naturally.
Async generators
const fakeApi = (page) =>
new Promise((r) => setTimeout(() => r({ items: [`p${page}-a`, `p${page}-b`], next: page < 3 ? page + 1 : null }), 5));
async function* paginate() {
let page = 1;
while (page) {
const { items, next } = await fakeApi(page);
yield* items;
page = next;
}
}
for await (const item of paginate()) {
console.log(item);
if (item === "p3-a") break;
}p1-a
p1-b
p2-a
p2-b
p3-afor await over promises and streams
const delays = [30, 10, 20].map((ms) => new Promise((r) => setTimeout(() => r(ms), ms)));
for await (const ms of delays) console.log("resolved", ms); // in ARRAY order, not finish order
import { Readable } from "node:stream";
const stream = Readable.from(["chunk1", "chunk2"]);
for await (const chunk of stream) console.log(chunk);
const collected = await Array.fromAsync(paginateSmall()); // ES2024
async function* paginateSmall() { yield 1; yield 2; }
console.log(collected);resolved 30
resolved 10
resolved 20
chunk1
chunk2
[ 1, 2 ]What is the difference between for...of and for await...of?