Перейти к содержимому

Generators

В одной фразе: генератор — функция, которая может приостанавливаться через yield и возобновляться, сохраняя весь локальный стек между вызовами. На собесе проверяют двустороннюю коммуникацию через next(value), методы return()/throw() и паттерны lazy evaluation.

// Двусторонняя коммуникация: next(value) передаёт значение в yield
function* dialog() {
const name = yield 'What is your name?'; // пауза 1: отдаём вопрос
const color = yield `Hi ${name}! Fav color?`; // пауза 2
return `${name} likes ${color}`; // done: true
}
const gen = dialog();
gen.next(); // { value: 'What is your name?', done: false }
gen.next('Alice'); // { value: 'Hi Alice! Fav color?', done: false }
gen.next('blue'); // { value: 'Alice likes blue', done: true }
gen.next(); // { value: undefined, done: true } — уже завершён
// Lazy sequences: вычисляется только по требованию
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
function* take(gen, n) {
for (const val of gen) {
yield val;
if (--n <= 0) return;
}
}
[...take(fibonacci(), 8)]; // [0, 1, 1, 2, 3, 5, 8, 13]
// yield* делегирует в другой iterable/generator
function* flatten(arr) {
for (const item of arr) {
if (Array.isArray(item)) yield* flatten(item); // рекурсивно
else yield item;
}
}
[...flatten([1, [2, [3, 4]], 5])]; // [1, 2, 3, 4, 5]
// return() и throw() управляют генератором извне
const gen = fibonacci();
gen.next(); // { value: 0, done: false }
gen.return(99); // { value: 99, done: true } — принудительное завершение
gen.next(); // { value: undefined, done: true } — уже завершён
// gen.throw(err) // бросает ошибку в точку yield

Итог: Генераторы — строительный блок для корутин, lazy evaluation и state machines. async/await реализован поверх генераторов внутри движка.