Learn how generator functions pause and resume execution to build lazy sequences and iterables.
function* to suspend and resume functions.yield keyword.yield* delegation.Symbol.iterator properties to create custom iterables cleanly.function* declarationDeclares generators which return an iterator object instead of running code.
function* counter() {
yield 1;
yield 2;
}
const it = counter();next() callsResumes execution block internally until encountering the next yield line.
it.next(); // { value: 1, done: false }
it.next(); // { value: 2, done: false }Return valuesSignals completion with done true and returns standard values if declared.
function* range() {
yield 1;
return "stop";
}
const it2 = range();
it2.next(); // { value: 1, done: false }
it2.next(); // { value: "stop", done: true }Value injectionPasses parameter values back into the generator at pause lines.
function* greet() {
const name = yield "name?";
yield `Hi, ${name}`;
}
const g = greet();
g.next(); // "name?"
g.next("Ada"); // { value: "Hi, Ada", done: false }return() methodTerminates generator runs early, returning specified values immediately.
const it = counter();
it.next();
it.return("end"); // { value: "end", done: true }throw() methodInjects exceptions directly into generators at the current yield line.
function* safe() {
try { yield 1; } catch (e) { yield e.message; }
}
const it = safe();
it.next();
it.throw(new Error("oops")); // value: "oops"Infinite generatorsComputes unending data streams on demand with zero memory leaks.
function* naturals() {
let n = 1;
while (true) yield n++;
}
const it = naturals();
it.next().value; // 1take() boundariesExtracts limited arrays from lazy sequences using break counters.
function take(iterable, count) {
const res = [];
for (const v of iterable) {
if (res.length >= count) break;
res.push(v);
}
return res;
}
take(naturals(), 3); // [1, 2, 3]Symbol.iterator methodAttaches generators to class object structures to allow for-of loops.
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
[...new Range(1, 3)]; // [1, 2, 3]Iterable forwardingDelegates execution directly to another iterable structure, avoiding loops.
function* combine() {
yield* [1, 2];
yield* "ab";
}
[...combine()]; // [1, 2, "a", "b"]Regular functions run to completion immediately when invoked. Generator functions, declared with function*, return an iterator instead. The function body runs only when calling .next().
The yield keyword pauses generator function execution and outputs a value to the caller. The generator remains frozen until the caller invokes .next() again.
Use yield* to forward values from another iterable, like an array or generator. This avoids manual loops and passes .next(), .return(), and .throw() down automatically.
The .return(value) method closes the generator early, returning the value. The .throw(error) method injects an exception at the current pause point, letting try/catch handle it.
Yes, they are. Assign a generator function to the object's Symbol.iterator property. The engine handles iterator tracking and value formats automatically under the hood.
Lazy Fibonacci Sequence Generator
Generates an infinite Fibonacci sequence lazily using destructuring assignment and a custom take controller.
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
function take(generator, count) {
const result = [];
for (const value of generator) {
if (result.length >= count) break;
result.push(value);
}
return result;
}
console.log(take(fibonacci(), 5)); // [1, 1, 2, 3, 5]Generators allow processing infinite data sequences safely by computing next values only when requested.