2.1 Generator Syntax
Generators in JavaScript are special functions that let you control code execution. They can pause their execution and resume later, making them a powerful tool for handling async code, iterators, and other complex tasks.
Generators are defined using the function*
keyword (note the asterisk).
Inside the generator, the yield
keyword is used to pause execution and return a value.
Declaring a Generator:
function* generatorFunction() {
yield 1;
yield 2;
yield 3;
}
Creating a Generator Object
Calling a generator doesn't run its code right away. Instead, it returns a generator object, which can be used to iterate over values:
const gen = generatorFunction();
2.2 Using Generators
The next() Method
The next()
method is used to resume the generator's execution up to the next yield
.
It returns an object with two properties:
value
: the value returned by theyield
statementdone
: a boolean that indicates if the generator is finished (true
) or not (false
)
Example of Using next() Method:
function* generatorFunction() {
yield 1;
yield 2;
yield 3;
}
const gen = generatorFunction();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
Iterating Over a Generator
Generators can be used with a for...of
loop to iterate over values.
Example of Iterating Over a Generator:
function* generatorFunction() {
yield 1;
yield 2;
yield 3;
}
const gen = generatorFunction();
for (const value of gen) {
console.log(value);
}
// Logs: 1
// Logs: 2
// Logs: 3
Example of Returning Values
Generators can return a value using the return
statement:
function* generatorFunction() {
yield 1;
yield 2;
return 3;
yield 4; // This yield will never run
}
const gen = generatorFunction();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: true }
console.log(gen.next()); // { value: undefined, done: true }
2.3 Advanced Generator Use Cases
Interacting with Generators
The next()
method can take an argument, which is passed into the generator and can be used inside it.
Example of Passing Values to a Generator:
function* generatorFunction() {
const value1 = yield 1;
const value2 = yield value1 + 2;
yield value2 + 3;
}
const gen = generatorFunction();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next(10)); // { value: 12, done: false }
console.log(gen.next(20)); // { value: 23, done: false }
console.log(gen.next()); // { value: undefined, done: true }
Error Handling
Generators allow error handling using a try...catch
block.
Example of Error Handling:
function* generatorFunction() {
try {
yield 1;
yield 2;
} catch (error) {
console.log('Error caught:', error);
}
}
const gen = generatorFunction();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.throw(new Error('Something went wrong'))); // Error caught: Error: Something went wrong
// { value: undefined, done: true }
Example of a Generator to Create an Infinite Sequence
Generators can be used to create infinite sequences of values:
function* infiniteSequence() {
let i = 0;
while (true) {
yield i++;
}
}
const gen = infiniteSequence();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// and so on
2.4 Practical Usage Examples
Example 1: Generator for Iterating Over an Object
function* objectEntries(obj) {
const keys = Object.keys(obj);
for (const key of keys) {
yield [key, obj[key]];
}
}
const obj = { a: 1, b: 2, c: 3 };
const gen = objectEntries(obj);
for (const [key, value] of gen) {
console.log(`${key}: ${value}`);
}
// Logs:
// a: 1
// b: 2
// c: 3
Example 2: Generator for Implementing a Simple Iterator
const myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
for (const value of myIterable) {
console.log(value);
}
// Logs: 1
// Logs: 2
// Logs: 3
Generators in JavaScript are a powerful tool for controlling code execution, creating iterators, and handling asynchronous operations. Understanding the syntax and use of generators helps create more flexible and readable code, especially when working with sequences of data and async tasks.
GO TO FULL VERSION