JavaScript Generators
Functions that can pause and resume execution
β‘ What are Generators?
Generators are special functions that can pause their execution and resume later. They use the function* syntax and yield keyword to produce a sequence of values.
// Basic generator function
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = simpleGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
Output:
Generator Features
Pausable
Can pause and resume execution
function* gen() {
yield 1; // Pause here
yield 2; // Resume and pause
}
Lazy Evaluation
Values computed on demand
function* infinite() {
let i = 0;
while (true) yield i++;
}
State Preservation
Remembers local variables
function* counter() {
let count = 0;
while (true) yield ++count;
}
Iterable
Works with for...of loops
for (const value of gen()) {
console.log(value);
}
πΉ Basic Generator Syntax
Generators use function* and yield keywords:
// Generator function declaration
function* numberGenerator() {
console.log('Generator started');
yield 1;
console.log('After first yield');
yield 2;
console.log('After second yield');
yield 3;
console.log('Generator finished');
}
// Create generator object
const gen = numberGenerator();
// Call next() to execute until next yield
console.log('Calling first next()');
console.log(gen.next()); // {value: 1, done: false}
console.log('Calling second next()');
console.log(gen.next()); // {value: 2, done: false}
console.log('Calling third next()');
console.log(gen.next()); // {value: 3, done: false}
console.log('Calling fourth next()');
console.log(gen.next()); // {value: undefined, done: true}
Output:
πΉ Generators with for...of
Generators are iterable and work perfectly with for...of:
function* fruitGenerator() {
yield 'apple';
yield 'banana';
yield 'orange';
}
// Use with for...of loop
console.log('Using for...of:');
for (const fruit of fruitGenerator()) {
console.log(fruit);
}
// Convert to array
const fruits = [...fruitGenerator()];
console.log('As array:', fruits);
Output:
πΉ Infinite Sequences
Generators can create infinite sequences efficiently:
// Infinite number sequence
function* infiniteNumbers() {
let num = 1;
while (true) {
yield num++;
}
}
// Fibonacci sequence generator
function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
// Use infinite generators (with limits!)
console.log('First 5 numbers:');
const numbers = infiniteNumbers();
for (let i = 0; i < 5; i++) {
console.log(numbers.next().value);
}
console.log('First 8 Fibonacci numbers:');
const fib = fibonacci();
for (let i = 0; i < 8; i++) {
console.log(fib.next().value);
}
Output:
πΉ Generator with Parameters
You can pass values back into generators using next():
function* interactiveGenerator() {
console.log('Generator started');
const firstInput = yield 'Give me a number';
console.log(`You gave me: ${firstInput}`);
const secondInput = yield 'Give me another number';
console.log(`You gave me: ${secondInput}`);
return firstInput + secondInput;
}
const gen = interactiveGenerator();
console.log(gen.next().value); // 'Give me a number'
console.log(gen.next(10).value); // 'Give me another number'
console.log(gen.next(20)); // {value: 30, done: true}
Output:
πΉ Practical Example: ID Generator
Create a unique ID generator using generators:
// ID Generator
function* createIdGenerator(prefix = 'ID') {
let id = 1;
while (true) {
yield `${prefix}-${String(id).padStart(4, '0')}`;
id++;
}
}
// User ID generator
const userIdGen = createIdGenerator('USER');
console.log('User IDs:');
for (let i = 0; i < 5; i++) {
console.log(userIdGen.next().value);
}
// Product ID generator
const productIdGen = createIdGenerator('PROD');
console.log('Product IDs:');
for (let i = 0; i < 3; i++) {
console.log(productIdGen.next().value);
}
// Order ID generator
const orderIdGen = createIdGenerator('ORD');
console.log('Order IDs:');
console.log(orderIdGen.next().value);
console.log(orderIdGen.next().value);
Output:
πΉ Generator Benefits
Why use generators?
- Memory Efficient: Generate values on demand
- Lazy Evaluation: Compute only when needed
- Infinite Sequences: Handle unlimited data
- State Management: Maintain state between calls
- Clean Code: Simpler than manual iterators