javascript

examples

examples.js
// ============================================
// 17.5 Generators - Examples
// ============================================

// --------------------------------------------
// 1. Basic Generator
// --------------------------------------------

function* simpleGenerator() {
  console.log('Start');
  yield 1;
  console.log('After first yield');
  yield 2;
  console.log('After second yield');
  yield 3;
  console.log('End');
}

const gen = simpleGenerator();

console.log(gen.next()); // Start, { value: 1, done: false }
console.log(gen.next()); // After first yield, { value: 2, done: false }
console.log(gen.next()); // After second yield, { value: 3, done: false }
console.log(gen.next()); // End, { value: undefined, done: true }

// --------------------------------------------
// 2. Generator Return Value
// --------------------------------------------

function* withReturn() {
  yield 1;
  yield 2;
  return 'finished';
}

const gen2 = withReturn();
console.log(gen2.next()); // { value: 1, done: false }
console.log(gen2.next()); // { value: 2, done: false }
console.log(gen2.next()); // { value: 'finished', done: true }
console.log(gen2.next()); // { value: undefined, done: true }

// Note: return value not included in for...of or spread
console.log([...withReturn()]); // [1, 2] (no 'finished')

// --------------------------------------------
// 3. Passing Values to Generators
// --------------------------------------------

function* conversation() {
  const name = yield 'What is your name?';
  const color = yield `Hello, ${name}! What's your favorite color?`;
  return `${name} likes ${color}`;
}

const chat = conversation();
console.log(chat.next()); // { value: "What is your name?", done: false }
console.log(chat.next('Alice')); // { value: "Hello, Alice! What's your favorite color?", done: false }
console.log(chat.next('blue')); // { value: "Alice likes blue", done: true }

// --------------------------------------------
// 4. Generator as Iterator
// --------------------------------------------

function* range(start, end) {
  for (let i = start; i <= end; i++) {
    yield i;
  }
}

// for...of
for (const num of range(1, 5)) {
  console.log(num); // 1, 2, 3, 4, 5
}

// Spread operator
console.log([...range(1, 5)]); // [1, 2, 3, 4, 5]

// Array.from
console.log(Array.from(range(1, 5))); // [1, 2, 3, 4, 5]

// Destructuring
const [a, b, c] = range(10, 20);
console.log(a, b, c); // 10, 11, 12

// --------------------------------------------
// 5. Infinite Generator
// --------------------------------------------

function* infiniteCounter() {
  let count = 0;
  while (true) {
    yield count++;
  }
}

const counter = infiniteCounter();
console.log(counter.next().value); // 0
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2
// Can continue forever...

// Take first N from infinite generator
function* take(iterable, n) {
  let count = 0;
  for (const item of iterable) {
    if (count++ >= n) return;
    yield item;
  }
}

console.log([...take(infiniteCounter(), 5)]); // [0, 1, 2, 3, 4]

// --------------------------------------------
// 6. yield* Delegation
// --------------------------------------------

function* delegateToArray() {
  yield 'start';
  yield* [1, 2, 3]; // Delegate to array
  yield 'end';
}

console.log([...delegateToArray()]); // ['start', 1, 2, 3, 'end']

function* delegateToString() {
  yield* 'Hello';
}

console.log([...delegateToString()]); // ['H', 'e', 'l', 'l', 'o']

function* inner() {
  yield 'a';
  yield 'b';
}

function* outer() {
  yield 1;
  yield* inner(); // Delegate to another generator
  yield 2;
}

console.log([...outer()]); // [1, 'a', 'b', 2]

// --------------------------------------------
// 7. yield* Return Value
// --------------------------------------------

function* innerWithReturn() {
  yield 1;
  yield 2;
  return 'inner done';
}

function* outerWithReturn() {
  const result = yield* innerWithReturn();
  console.log('Inner returned:', result);
  yield 3;
}

console.log([...outerWithReturn()]);
// Inner returned: inner done
// [1, 2, 3]

// --------------------------------------------
// 8. Generator throw() Method
// --------------------------------------------

function* withErrorHandling() {
  try {
    yield 1;
    yield 2;
  } catch (e) {
    console.log('Caught:', e);
    yield 'error handled';
  }
  yield 3;
}

const errGen = withErrorHandling();
console.log(errGen.next()); // { value: 1, done: false }
console.log(errGen.throw(new Error('Oops!'))); // Caught: Error: Oops!, { value: 'error handled', done: false }
console.log(errGen.next()); // { value: 3, done: false }

// --------------------------------------------
// 9. Generator return() Method
// --------------------------------------------

function* cleanupGenerator() {
  try {
    yield 1;
    yield 2;
    yield 3;
  } finally {
    console.log('Cleanup executed');
  }
}

const cleanGen = cleanupGenerator();
console.log(cleanGen.next()); // { value: 1, done: false }
console.log(cleanGen.return('early exit')); // Cleanup executed, { value: 'early exit', done: true }
console.log(cleanGen.next()); // { value: undefined, done: true }

// --------------------------------------------
// 10. Fibonacci Generator
// --------------------------------------------

function* fibonacci() {
  let prev = 0,
    curr = 1;
  while (true) {
    yield curr;
    [prev, curr] = [curr, prev + curr];
  }
}

const fib = fibonacci();
console.log([...take(fib, 10)]);
// [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

// --------------------------------------------
// 11. Tree Traversal with Generator
// --------------------------------------------

class TreeNode {
  constructor(value, left = null, right = null) {
    this.value = value;
    this.left = left;
    this.right = right;
  }

  // In-order traversal
  *[Symbol.iterator]() {
    if (this.left) yield* this.left;
    yield this.value;
    if (this.right) yield* this.right;
  }
}

const tree = new TreeNode(
  4,
  new TreeNode(2, new TreeNode(1), new TreeNode(3)),
  new TreeNode(6, new TreeNode(5), new TreeNode(7))
);

console.log([...tree]); // [1, 2, 3, 4, 5, 6, 7]

// --------------------------------------------
// 12. Generator-based State Machine
// --------------------------------------------

function* trafficLight() {
  while (true) {
    yield 'green';
    yield 'yellow';
    yield 'red';
  }
}

const light = trafficLight();
console.log(light.next().value); // 'green'
console.log(light.next().value); // 'yellow'
console.log(light.next().value); // 'red'
console.log(light.next().value); // 'green'

// --------------------------------------------
// 13. ID Generator
// --------------------------------------------

function* idGenerator(prefix = 'id') {
  let id = 0;
  while (true) {
    yield `${prefix}_${id++}`;
  }
}

const userIds = idGenerator('user');
const orderIds = idGenerator('order');

console.log(userIds.next().value); // 'user_0'
console.log(userIds.next().value); // 'user_1'
console.log(orderIds.next().value); // 'order_0'
console.log(userIds.next().value); // 'user_2'

// --------------------------------------------
// 14. Paginated Data Generator
// --------------------------------------------

function* paginatedData(data, pageSize) {
  for (let i = 0; i < data.length; i += pageSize) {
    yield {
      page: Math.floor(i / pageSize) + 1,
      items: data.slice(i, i + pageSize),
      hasMore: i + pageSize < data.length,
    };
  }
}

const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const pages = paginatedData(items, 3);

console.log(pages.next().value);
// { page: 1, items: [1, 2, 3], hasMore: true }

console.log(pages.next().value);
// { page: 2, items: [4, 5, 6], hasMore: true }

// --------------------------------------------
// 15. Async Generator (ES2018)
// --------------------------------------------

async function* asyncGenerator() {
  yield await Promise.resolve(1);
  yield await Promise.resolve(2);
  yield await Promise.resolve(3);
}

// Using async iteration
(async () => {
  for await (const value of asyncGenerator()) {
    console.log(value); // 1, 2, 3
  }
})();

// Simulating API pagination
async function* fetchPages(baseUrl, maxPages = 3) {
  for (let page = 1; page <= maxPages; page++) {
    // Simulate API call
    const data = await new Promise((resolve) =>
      setTimeout(() => resolve({ page, items: [page * 10] }), 100)
    );
    yield data;
  }
}

(async () => {
  for await (const page of fetchPages('/api/items')) {
    console.log('Fetched:', page);
  }
})();

// --------------------------------------------
// 16. Combining Multiple Generators
// --------------------------------------------

function* merge(...generators) {
  for (const gen of generators) {
    yield* gen;
  }
}

function* evens() {
  yield 2;
  yield 4;
  yield 6;
}

function* odds() {
  yield 1;
  yield 3;
  yield 5;
}

console.log([...merge(evens(), odds())]);
// [2, 4, 6, 1, 3, 5]

// Interleaved merge
function* interleave(...generators) {
  const iterators = generators.map((g) => g[Symbol.iterator]());
  let active = iterators.length;

  while (active > 0) {
    for (let i = 0; i < iterators.length; i++) {
      if (iterators[i]) {
        const { value, done } = iterators[i].next();
        if (done) {
          iterators[i] = null;
          active--;
        } else {
          yield value;
        }
      }
    }
  }
}

console.log([...interleave(evens(), odds())]);
// [2, 1, 4, 3, 6, 5]
Examples - JavaScript Tutorial | DeepML