javascript
examples
examples.js⚡javascript
// ============================================
// 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]