Генераторы и ключевое слово yield в JavaScript: просто о сложном
Если вы впервые сталкиваетесь с генераторами, скорее всего, вам покажется, что это просто еще один способ писать функции. На самом деле, это мощный инструмент для управления потоком данных, ленивых вычислений и асинхронного программирования. Давайте разберемся, что такое генераторы и yield в JavaScript, как они работают, и какие подводные камни часто поджидают новичков.
Как работают генераторы в JS
Функция-генератор: отличие от обычной функции

Генераторы JavaScript — это особый вид функций, которые могут приостанавливать и возобновлять своё выполнение. Они объявляются с помощью звёздочки: function*. Вместо return они используют yield, который "замораживает" выполнение функции, сохраняя её состояние.
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
Если вызвать simpleGenerator(), мы получим не результат, а объект-итератор. Чтобы получить значения, нужно вызывать его метод next():
const gen = simpleGenerator();
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 }
Состояние сохраняется между вызовами next(). Это и есть суть того, как работают генераторы в JS — ленивое выполнение и контроль над потоком.
Что делает yield в JavaScript
Ключевое слово yield в JavaScript выполняет двойную функцию: оно возвращает значение наружу и приостанавливает исполнение генератора. При следующем вызове next() выполнение продолжается с момента последнего yield.
Можно также передавать данные обратно в генератор:
function* echo() {
const x = yield "Введите значение";
console.log("Вы ввели:", x);
}
const it = echo();
console.log(it.next().value); // "Введите значение"
it.next("Привет, мир"); // Вы ввели: Привет, мир
Это делает генераторы отличным выбором для построения потоков данных, пайплайнов и даже простых кооперативных корутин.
Практические примеры генераторов в JavaScript
1. Генерация бесконечной последовательности
Допустим, нам нужно получить бесконечный поток чисел Фибоначчи. Генераторы идеально подходят для таких задач — создают значения по запросу, не расходуя лишнюю память.
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
2. Управление асинхронным кодом
До появления async/await генераторы активно использовались в библиотеках типа co для пошагового выполнения асинхронных операций:
function* fetchData() {
const user = yield fetch('/api/user');
const posts = yield fetch(`/api/posts?user=${user.id}`);
return posts;
}
Такое использование yield в JavaScript позволяет писать асинхронный код в синхронном стиле — особенно полезно, когда нужно последовательно выполнять несколько запросов.
Частые ошибки при работе с генераторами
Ошибка 1: ожидание немедленного результата
Многие начинающие разработчики думают, что вызов генератора сразу вернёт нужное значение. Но на самом деле function* возвращает итератор, а не результат. Нужно явно вызывать next().
- Неверно:
const result = generatorFunction(); - Правильно:
const result = generatorFunction().next().value;
Ошибка 2: забывают про done

Каждый объект, возвращаемый next(), содержит флаг done. Он сигнализирует, завершена ли работа генератора. Новички часто не проверяют его, что может привести к неожиданным багам, особенно в циклах.
Ошибка 3: неправильное использование yield в выражении
Внутри генератора yield можно использовать как выражение. Но если его поместить, например, в арифметику или логическое выражение без скобок, можно получить синтаксическую ошибку.
// Неправильно
const x = 1 + yield 2; // Ошибка
// Правильно
const x = 1 + (yield 2);
Когда стоит использовать генераторы
Генераторы — не панацея, но в ряде случаев они дают значительные преимущества:
- Обработка больших или бесконечных потоков данных без нагрузки на память
- Построение ленивых вычислений (например, фильтрация или маппинг коллекций)
- Управление сложной асинхронной логикой до появления
async/await
Например, если у вас есть большой CSV-файл, который вы читаете построчно, можно использовать генератор для построчной обработки, не загружая весь файл в память. Это особенно актуально для Node.js-серверов с ограниченным объёмом оперативки.
Итог: стоит ли учить генераторы?
Однозначно да. Пусть они и не так часто используются в повседневной разработке, понимание того, как работают генераторы в JS, открывает двери к более глубокому пониманию итераторов, асинхронности и контроля выполнения. Плюс, это просто элегантный инструмент, который приятно использовать, когда знаешь, как.
Если вы начали изучать генераторы JavaScript, экспериментируйте: создайте свой пайплайн, итератор или даже мини-фреймворк на их основе. И главное — не забывайте про yield. Он не просто возвращает значение, он управляет потоком.



