Fundamentals 11 min read

Understanding JavaScript Generators: Basics, Syntax, and Advanced Usage

JavaScript Generators, introduced in ES6, allow functions to pause and resume execution, yielding multiple values; this article explains their syntax, basic usage, advanced features like yield* and data exchange, and demonstrates practical scenarios such as asynchronous flow control, memory-efficient data processing, and state machine implementation.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Understanding JavaScript Generators: Basics, Syntax, and Advanced Usage

JavaScript Generator functions, added in ES6, provide a way to produce a sequence of values while allowing the function to pause and later resume execution. Although they are less frequently used than async/await in many projects, they excel in complex flow‑control and state‑management scenarios.

Generator Overview

A JavaScript Generator is a special type of function that can generate multiple values over time. When a function is declared with an asterisk ( function* ), it becomes a generator. Inside the generator, the yield keyword defines each value to be returned to the caller.

Basic Syntax

Generators are defined using the function* syntax and can contain multiple yield expressions:

function* myGenerator() {
  // Generator body
}

Example:

function* myGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

Calling a generator does not execute its body immediately; it returns an iterator object. The iterator’s next() method runs the function until the next yield , returning an object with value and done properties.

const myGeneratorIterator = myGenerator();
console.log(myGeneratorIterator.next()); // { value: 1, done: false }
console.log(myGeneratorIterator.next()); // { value: 2, done: false }
console.log(myGeneratorIterator.next()); // { value: 3, done: false }
console.log(myGeneratorIterator.next()); // { value: undefined, done: true }

Advanced Usage

yield* Expression

The yield* expression delegates yielding to another generator or iterable, effectively flattening nested sequences.

function* foo() {
  yield 1;
  yield 2;
}
function* bar() {
  yield* foo();
  yield 3;
}
for (let value of bar()) {
  console.log(value); // 1, 2, 3
}

Data Interaction

Generators can receive data from the caller via next(value) . The value passed to next() becomes the result of the paused yield expression.

function* foo() {
  let x = yield;
  yield x * 2;
}
let gen = foo();
gen.next(); // start generator
gen.next(10); // passes 10, yields 20

Asynchronous Programming

By yielding Promise objects, generators can orchestrate asynchronous operations without async/await :

function* myGenerator() {
  const result1 = yield new Promise(resolve => setTimeout(() => resolve('first'), 1000));
  console.log(result1);
  const result2 = yield new Promise(resolve => setTimeout(() => resolve('second'), 2000));
  console.log(result2);
  const result3 = yield new Promise(resolve => setTimeout(() => resolve('third'), 3000));
  console.log(result3);
}
const generator = myGenerator();
const promise = generator.next().value;
promise.then(result => generator.next(result).value)
       .then(result => generator.next(result).value)
       .then(result => generator.next(result).value);

Advantages and Disadvantages

More flexible control flow for complex asynchronous sequences.

Generator state can be saved and resumed, enabling reuse.

Works with a wide range of async patterns, including callbacks, events, and promises.

Higher code complexity and reduced readability compared to async/await .

Practical Scenarios

Controlling Asynchronous Flow

Fetching data from multiple APIs sequentially can be expressed cleanly with a generator:

function* fetchAllData() {
  const data1 = yield fetch('api1');
  const data2 = yield fetch('api2');
  const data3 = yield fetch('api3');
  return [data1, data2, data3];
}
function run(generator) {
  const iterator = generator();
  function handle(iteratorResult) {
    if (iteratorResult.done) {
      return Promise.resolve(iteratorResult.value);
    }
    return Promise.resolve(iteratorResult.value)
      .then(res => handle(iterator.next(res)));
  }
  return handle(iterator.next());
}
run(fetchAllData).then(data => console.log(data));

Processing Large Data Sets

Generators enable lazy evaluation, reducing memory usage when handling big data:

function* dataGenerator() {
  let index = 0;
  while (true) {
    yield index++;
  }
}
function* processData(data, processFn) {
  for (let item of data) {
    yield processFn(item);
  }
}
const data = dataGenerator();
const processedData = processData(data, item => item * 2);
for (let i = 0; i < 500; i++) {
  console.log(processedData.next().value);
}

State Machine Implementation

Generators can model state machines, where each yield represents a transition:

function* stateMachine() {
  let state = 'start';
  while (true) {
    switch (state) {
      case 'start':
        console.log('Enter start state');
        state = yield 'start';
        break;
      case 'middle':
        console.log('Enter middle state');
        state = yield 'middle';
        break;
      case 'end':
        console.log('Enter end state');
        state = yield 'end';
        break;
    }
  }
}
const sm = stateMachine();
console.log(sm.next().value); // start
console.log(sm.next('middle').value); // middle
console.log(sm.next('end').value); // end

Conclusion

While async/await offers a simpler syntax for most asynchronous tasks, Generator functions remain valuable for intricate control flows, custom state machines, and memory‑efficient data processing, providing developers with a powerful tool when needed.

JavaScriptData ProcessingState MachineAsyncgeneratoryield
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.