Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An asynchronous generator function is a construct declared with async function* that combines the pause-and-resume execution model of generators with the non-blocking, Promise-based resolution of asynchronous functions. Invoking this function does not execute its body immediately; instead, it returns an AsyncGenerator object that conforms to both the AsyncIterable and AsyncIterator protocols.

Type Signature

In TypeScript, the return type of an async generator is explicitly typed using the built-in AsyncGenerator<T, TReturn, TNext> interface.
async function* asyncGeneratorName(): AsyncGenerator<YieldType, ReturnType, NextType> {
    // Function body
}
  • YieldType (T): The type of the values emitted by the yield keyword.
  • ReturnType (TReturn): The type of the final value returned by the function when it completes (via the return statement). In the TypeScript standard library interface, this defaults to any.
  • NextType (TNext): The type of the value injected back into the generator when calling .next(value). In the TypeScript standard library interface, this defaults to unknown.

Execution Mechanics

  1. Awaiting and Yielding: Inside the function body, you can use await to pause execution until a Promise settles. You use yield to emit a value to the consumer.
  2. Promise Wrapping: Unlike synchronous generators that return an IteratorResult directly, an async generator’s .next() method always returns a Promise that resolves to an IteratorResult object: { value: T | TReturn, done: boolean }.
  3. Two-way Communication: The generator pauses at each yield. When the consumer calls .next(argument), the generator resumes, and the argument becomes the evaluated result of the yield expression.
  4. Promise Queueing: If multiple .next() calls are made synchronously before previous ones resolve, the async generator queues them internally. Each .next() call waits for the preceding iteration to fully complete (including any internal await operations) before executing, ensuring strict sequential execution.

Syntax Visualization

The following example demonstrates the type annotations, internal await mechanics, and two-way communication via yield. The NextType includes undefined to safely accommodate constructs that do not pass arguments to .next().
// AsyncGenerator<YieldType, ReturnType, NextType>
async function* statefulAsyncGenerator(): AsyncGenerator<number, string, boolean | undefined> {
    // Pauses execution, yields 1. 
    // Awaits a boolean (or undefined) injection from the next .next(value) call.
    const shouldContinue: boolean | undefined = yield 1; 

    // Abort if explicitly instructed via .next(false)
    if (shouldContinue === false) {
        return "Aborted"; // Resolves Promise with { value: "Aborted", done: true }
    }

    // Standard async/await behavior is permitted internally
    await new Promise(resolve => setTimeout(resolve, 100));

    yield 2;

    return "Completed";
}

Consumption Mechanics

Because the generator yields Promises, it cannot be consumed by a standard for...of loop. It must be consumed asynchronously. Manual Iteration via .next() When calling .next() manually, you can leverage the internal Promise queueing mechanism. Synchronous calls to .next() will automatically wait for their turn in the queue.
const iterator = statefulAsyncGenerator();

// The first .next() starts the generator. No value can be injected here.
iterator.next().then(result => {
    console.log(result); // { value: 1, done: false }
});

// Queued internally: waits for the first yield to settle, then injects 'true'.
iterator.next(true).then(result => {
    console.log(result); // { value: 2, done: false }
});

// Queued internally: waits for the second yield to settle, then injects 'true'.
iterator.next(true).then(result => {
    console.log(result); // { value: "Completed", done: true }
});
Iteration via for await...of TypeScript supports the for await...of statement to automatically consume AsyncIterable objects. This approach automatically awaits each yielded Promise, extracts the value, and terminates when done: true. Note that for await...of calls .next() without any arguments. This means undefined is injected into the generator at every step.
async function consumeGenerator() {
    const iterator = statefulAsyncGenerator();
    
    // Automatically calls .next() without arguments (injecting undefined).
    // Because shouldContinue evaluates to undefined, the generator does not abort.
    for await (const value of iterator) {
        console.log(value); // Logs: 1, then 2
        // Note: The return value ("Completed") is ignored by for await...of
    }
}
Master TypeScript with Deep Grasping Methodology!Learn More