JavaScript - Generators
JavaScript Generators are special types of functions that allow you to pause and resume execution. Unlike regular functions that run to completion once called, generators provide more control by producing values one at a time, on-demand, using the yield keyword.
1. What Are Generators?
Generators are functions that:
Can pause execution at any point using yield.
Can resume execution where they left off.
Return an iterator object when invoked.
Generators provide a powerful way to handle asynchronous operations, iterators, and infinite sequences.
2. Syntax of a Generator Function
Generator functions are defined using the function* syntax. The * indicates that the function is a generator.
Example:
function* generatorFunction() {
yield "First value";
yield "Second value";
return "Final value";
}
3. Using yield in Generators
The yield keyword is used to pause the execution of the generator and return a value.
Example:
function* greet() {
yield "Hello";
yield "How are you?";
yield "Goodbye!";
}
const generator = greet();
console.log(generator.next().value); // Logs: "Hello"
console.log(generator.next().value); // Logs: "How are you?"
console.log(generator.next().value); // Logs: "Goodbye!"
console.log(generator.next().value); // Logs: undefined (no more yields)
4. The next() Method
The generator object returned by a generator function implements the iterator protocol. The next() method:
Resumes execution until the next yield.
Returns an object with two properties:
value: The value of the current yield expression.
done: A boolean indicating if the generator has completed execution.
Example:
function* numbers() {
yield 1;
yield 2;
yield 3;
}
const iterator = numbers();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
5. Generator Example: Infinite Sequence
Generators can create infinite sequences, which are useful for tasks like pagination or streaming data.
Example:
function* infiniteNumbers() {
let number = 1;
while (true) {
yield number++;
}
}
const sequence = infiniteNumbers();
console.log(sequence.next().value); // Logs: 1
console.log(sequence.next().value); // Logs: 2
console.log(sequence.next().value); // Logs: 3
6. Delegating Generators
Generators can delegate control to another generator using the yield* keyword.
Example:
function* subGenerator() {
yield "Sub-generator value 1";
yield "Sub-generator value 2";
}
function* mainGenerator() {
yield "Main generator value";
yield* subGenerator();
yield "Another main generator value";
}
const iterator = mainGenerator();
for (const value of iterator) {
console.log(value);
}
// Logs:
// "Main generator value"
// "Sub-generator value 1"
// "Sub-generator value 2"
// "Another main generator value"
7. Use Cases of Generators
a. Asynchronous Programming
Generators can be used with Promise or libraries like co to handle asynchronous tasks in a sequential manner.
function* asyncGenerator() {
console.log("Start");
yield new Promise((resolve) => setTimeout(() => resolve("First async value"), 1000));
yield new Promise((resolve) => setTimeout(() => resolve("Second async value"), 2000));
}
const generator = asyncGenerator();
generator.next().value.then(console.log); // Logs: "First async value"
generator.next().value.then(console.log); // Logs: "Second async value"
b. Lazy Evaluation
Generators produce values on demand, making them ideal for large data sets or sequences.
c. Iterating Over Data
Generators can replace complex iterators for custom looping logic.
8. Conclusion
JavaScript generators are a versatile and powerful feature for managing control flow, particularly in asynchronous programming and lazy evaluation. With their ability to pause and resume execution, generators open up new possibilities for clean and efficient code.
Key Points:
Generators use function* and yield.
They return an iterator object with the next() method.
Generators are ideal for asynchronous operations, lazy evaluation, and custom iterators.