Master JavaScript Generators: Control Iteration and Boost Your Code
This article explains ES6 JavaScript generators, covering their syntax, how they differ from regular iterators, the role of the yield keyword, available generator methods, and practical examples such as custom generators, random number streams, throttling, Fibonacci sequences, and integrating generators with HTML to simplify iterative tasks.
Original source: What are JavaScript Generators and how to use them Translation source: 什么是 JavaScript generator 以及如何使用它们 Translator: li-z Proofreader: 张舰, 赵冉
What is JavaScript generator and how to use it
In this article we introduce ES6 generators and show usage examples.
What is a JavaScript generator
Generators are functions that control an iterator, allowing the execution to be paused and resumed at any time.
The following examples illustrate what a generator is and how it differs from a regular for loop.
<code>for (let i = 0; i < 5; i++) {
console.log(i);
}
// outputs 0 -> 1 -> 2 -> 3 -> 4</code>Now see a generator function:
<code>function* generatorForLoop(num) {
for (let i = 0; i < num; i++) {
yield console.log(i);
}
}
const genForLoop = generatorForLoop(5);
genForLoop.next(); // logs 0
genForLoop.next(); // logs 1
genForLoop.next(); // logs 2
genForLoop.next(); // logs 3
genForLoop.next(); // logs 4
</code>The key difference is that the generator does not execute immediately; it yields values only when next() is called.
Generator syntax
A generator function is declared by placing an asterisk after the function keyword.
<code>function* generator() {}
let generator = function*() {};
// Arrow functions cannot be used to create generators</code>Generators can also be defined as methods inside classes or objects:
<code>class MyClass {
*generator() {}
}
const obj = {
*generator() {}
};</code>Yield
The yield keyword works like return but allows the function to pause and later resume.
<code>function withReturn(a) {
let b = 5;
return a + b;
b = 6; // never executed
return a * b; // never executed
}
withReturn(6); // 11
</code>In contrast, yield can be called multiple times:
<code>function* withYield(a) {
let b = 5;
yield a + b;
b = 6;
yield a * b;
}
const calcSix = withYield(6);
calcSix.next().value; // 11
calcSix.next().value; // 36
</code>A generator returns an object with value and done properties. value holds the yielded value, while done indicates whether the generator has finished.
<code>function* generator() {
yield 5;
}
const gen = generator();
gen.next(); // {value: 5, done: false}
gen.next(); // {value: undefined, done: true}
</code>Both return and throw can be used inside generators. return() ends the generator early, setting done to true, while throw() propagates an error that can be caught with try‑catch .
<code>function* generator() {
yield 1;
yield 2;
yield 3;
}
const gen = generator();
gen.return('Finished'); // {value: 'Finished', done: true}
</code>Implement custom methods
Because generator functions are not global constructors, custom methods can be added via the prototype chain:
<code>function* generator() {
yield 1;
}
generator.prototype.__proto__.math = function(e = 0) {
return e * Math.PI;
};
const gen = generator();
gen.math(1); // 3.141592653589793
</code>Purpose of generators
Generators can produce infinite sequences, such as random numbers:
<code>function* randomFrom(...arr) {
while (true) {
yield arr[Math.floor(Math.random() * arr.length)];
}
}
const getRandom = randomFrom(1,2,5,9,4);
getRandom.next().value; // random element from the array
</code>They are also useful for implementing throttling:
<code>function* throttle(func, time) {
let timerID = null;
function throttled(arg) {
clearTimeout(timerID);
timerID = setTimeout(func.bind(window, arg), time);
}
while (true) {
yield throttled(yield);
}
}
const thr = throttle(console.log, 1000);
thr.next();
thr.next('hello'); // logs 'hello' after 1 second
</code>And for generating Fibonacci numbers without recursion:
<code>function* fibonacci(seed1, seed2) {
while (true) {
yield (() => {
seed2 = seed2 + seed1;
seed1 = seed2 - seed1;
return seed2;
})();
}
}
const fib = fibonacci(0, 1);
fib.next(); // {value: 1, done: false}
fib.next(); // {value: 2, done: false}
</code>Using generators in HTML
Generators can be combined with DOM manipulation to apply classes to elements lazily:
<code>const strings = document.querySelectorAll('.string');
const btn = document.querySelector('#btn');
const className = 'darker';
function* addClassToEach(elements, className) {
for (const el of Array.from(elements))
yield el.classList.add(className);
}
const addClassToStrings = addClassToEach(strings, className);
btn.addEventListener('click', () => {
if (addClassToStrings.next().done)
btn.classList.add(className);
});
</code>Conclusion
Generators offer many possibilities, from simplifying asynchronous code to creating on‑demand iterables. They enable you to retrieve the next value only when needed, making them a powerful tool for modern JavaScript development.
Yuewen Frontend Team
Click follow to learn the latest frontend insights in the cultural content industry. We welcome you to join us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.