Suggest an editImprove this articleRefine the answer for “Async generator”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`async function*` is a function that hands out asynchronous values one portion at a time.** It creates an async iterator whose `.next()` returns a `Promise` that resolves to `{ value, done }` instead of a plain object. Inside it you can freely mix `await` (wait for a request, a timer, a file read) and `yield` (push the next portion out). You can only iterate such a generator with `for await...of`, because it implements `[Symbol.asyncIterator]`, not `[Symbol.iterator]`. ```javascript async function* numbers() { for (let i = 1; i <= 3; i++) { await new Promise(r => setTimeout(r, 1000)); yield i; } } for await (const n of numbers()) console.log(n); // 1, 2, 3 ``` **Key point:** `function*` gives you a synchronous sequence, `async function*` gives you an asynchronous one, one value at a time, consumed with `for await...of`.Shown above the full answer for quick recall.Answer (EN)Image**An async generator (`async function*`) is a function that hands out asynchronous values step by step.** It creates an async iterator whose `.next()` method returns a `Promise` rather than a plain `{ value, done }` object. ## Theory ### TL;DR - Declaration: `async function* name() { ... }`, that is `async` plus an asterisk. - It returns an async iterator; `.next()` gives you a `Promise<{ value, done }>`. - Both `await` and `yield` are allowed inside, so you can run requests, pauses or database reads between steps. - It is iterated only with `for await...of`; a plain `for...of` does not work, because it implements `[Symbol.asyncIterator]`. - It supports delegation with `yield*`, plus the control methods `.return()` and `.throw()`. - Typical uses: data streaming, paginated APIs, lazy loading, asynchronous pipelines. ### Quick example ```javascript async function* fetchNumbers() { yield 1; yield 2; yield 3; } (async () => { for await (const n of fetchNumbers()) { console.log(n); } })(); ``` Output: ```javascript 1 2 3 ``` The difference from a regular `function*`: every value is returned asynchronously, through a `Promise`, so the only way to consume it is `for await...of`. ### Async yield: waiting between steps Async generators earn their keep exactly when there are asynchronous actions between iterations: `fetch`, `await`, `setTimeout`, database queries and so on. ```javascript async function* delayedNumbers() { for (let i = 1; i <= 3; i++) { await new Promise(resolve => setTimeout(resolve, 1000)); // wait 1 second yield i; } } (async () => { for await (const n of delayedNumbers()) { console.log(n); } })(); ``` Output (with a one second pause between the numbers): ```javascript 1 2 3 ``` Here the generator waits asynchronously inside `await` and then hands out the next value with `yield`. On every iteration `for await...of` implicitly awaits the result of `.next()`. ### What an async generator returns If you crank the iterator by hand, every `.next()` has to be awaited: ```javascript const gen = delayedNumbers(); console.log(await gen.next()); // { value: 1, done: false } console.log(await gen.next()); // { value: 2, done: false } console.log(await gen.next()); // { value: 3, done: false } console.log(await gen.next()); // { value: undefined, done: true } ``` > `gen.next()` returns a `Promise` that resolves to `{ value, done }`. An async generator returns an object with the method: ```javascript [Symbol.asyncIterator]() ``` which returns itself. Such an object can be iterated only with `for await...of`, never with `for...of`. Just like a regular generator, an async one supports delegation with `yield*`, that is nesting another async generator: ```javascript async function* sub() { yield 1; yield 2; } async function* main() { yield* sub(); // delegates the iteration yield 3; } for await (const v of main()) { console.log(v); } ``` Output: ```javascript 1 2 3 ``` The control methods `.return()` and `.throw()` work as well: ```javascript async function* gen() { try { yield 1; yield 2; } catch (e) { console.log('Error inside:', e.message); } finally { console.log('Generator finished'); } } const iterator = gen(); console.log(await iterator.next()); // { value: 1, done: false } console.log(await iterator.throw(new Error("fail"))); // Error inside: fail // Generator finished ``` ### Data streams and async pipelines Async generators are a perfect fit for streaming data processing: ```javascript async function* streamData(urls) { for (const url of urls) { const res = await fetch(url); const data = await res.json(); yield data; } } (async () => { const urls = [ '/api/user', '/api/posts', '/api/comments' ]; for await (const chunk of streamData(urls)) { console.log('Data:', chunk); } })(); ``` Here each `fetch()` runs in turn, and after every `yield` the data is handed out into the `for await...of` loop. Several generators can be nested into one another like links of a conveyor: ```javascript async function* generateNumbers() { for (let i = 1; i <= 10; i++) { await new Promise(r => setTimeout(r, 200)); yield i; } } async function* filterEven(source) { for await (const n of source) { if (n % 2 === 0) yield n; } } async function* double(source) { for await (const n of source) { yield n * 2; } } // Combining several async generators: (async () => { const pipeline = double(filterEven(generateNumbers())); for await (const value of pipeline) { console.log(value); // 4, 8, 12, 16, 20 } })(); ``` This is lazy asynchronous data processing, essentially a stream pipeline: nothing is computed up front, and every link pulls the next value only when it is asked for. ### Where it is used, and a summary | Scenario | How it is used | | --- | --- | | **Data streaming** | Gradually loading parts of a file or of a server response | | **Incremental requests** | Working with an API that returns data in "pages" | | **Lazy computation** | Producing values as they are needed | | **Async pipelines** | Combining several data sources | | **Node.js Streams** | Compatible with the `ReadableStream` and `AsyncIterator` interfaces | Summary: | Feature | Description | | --- | --- | | Declaration | `async function* name() { ... }` | | Returns | An async iterator | | The `.next()` method | Returns `Promise<{ value, done }>` | | Used with | `for await...of` | | `yield` | Hands out intermediate values asynchronously | | Applications | Data streams, paginated APIs, lazy loading, event generation | The main idea in one line: `function*` gives synchronous sequences, while `async function*` gives asynchronous ones, for example "one request at a time". ### Common mistakes - **Iterating an async generator with `for...of`.** That throws, because the object implements `[Symbol.asyncIterator]`, not `[Symbol.iterator]`; you need `for await...of`. - **Forgetting `await` before `.next()`.** Without it you get a `Promise`, not `{ value, done }`, and the `done` check is always `undefined`. - **Using `for await...of` outside an async context.** It only works inside an `async` function or in a module that supports top-level `await`. - **Expecting parallelism.** An async generator is sequential: the next `fetch` starts only after the previous value has been taken. For parallel requests you need `Promise.all`, not a generator. - **Putting `yield` inside `forEach` or another callback.** `yield` only works in the body of the generator itself, so use plain `for` or `for await...of` loops. - **Not closing the generator.** If you leave the loop with `break` or `return`, the engine calls `.return()`, so resources such as connections and streams should be released in a `finally` block.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.