JS Advanced

Генераторы и итераторы

Понять, как function* создаёт генератор, как yield приостанавливает выполнение, и как генераторы связаны с итераторами и for...of.

Продвинутый (Advanced)

Кратко

Generator — функция, которая может приостановить выполнение (yield) и возобновить (next()). Генератор возвращает итератор: next() возвращает {value, done}. yield — точка приостановки. for...of работает с итераторами автоматически.


Подробно

Создание генератора: function* count() { yield 1; yield 2; yield 3; }

const gen = count(); 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 }

yield — точка приостановки: function* range(start, end) { for (let i = start; i <= end; i++) { yield i; } }

for (const num of range(1, 5)) { console.log(num); // 1, 2, 3, 4, 5 }

yield* — делегирование: function* concat(iter1, iter2) { yield* iter1; yield* iter2; }

// Кастомный итератор: class Fibonacci { constructor(limit) { this.limit = limit; } [Symbol.iterator]() { let a = 0, b = 1, count = 0; const limit = this.limit; return { next() { if (count >= limit) return { done: true }; const value = a; [a, b] = [b, a + b]; count++; return { value, done: false }; } }; } }

for (const n of new Fibonacci(5)) { console.log(n); // 0, 1, 1, 2, 3 }


Ментальная модель

Generator — как книга с закладками. yield — закладка: «Прочитай до сюда, потом вернись». next() — «Продолжи читать от последней закладки». Когда книга закончена — done: true.


Примеры

**Самый простой:**

javascript
function* oneTwo() {
  yield 1;
  yield 2;
}

const gen = oneTwo();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: undefined, done: true }

Простейший генератор: два yield.

**Простой:**

javascript
function* fibonacci() {
  let a = 0, b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

const fib = fibonacci();
for (let i = 0; i < 8; i++) {
  console.log(fib.next().value); // 0, 1, 1, 2, 3, 5, 8, 13
}

Бесконечный генератор: Fibonacci без ограничения.

**Реальный пример:**

javascript
// Генератор для чтения файла построчно
function* readLines(text) {
  const lines = text.split('\n');
  for (let i = 0; i < lines.length; i++) {
    yield { lineNumber: i + 1, content: lines[i] };
  }
}

const csv = 'Name,Age\nАнна,25\nБорис,30';
for (const line of readLines(csv)) {
  console.log(`${line.lineNumber}: ${line.content}`);
}
// 1: Name,Age
// 2: А́нна,25
// 3: Борис,30

Генератор для обработки данных построчно.


Частые ошибки

**Неправильно:** Думать, что yield останавливает весь код

**Почему:** yield останавливает ТОЛЬКО генератор. Остальной код продолжает выполняться.

**Правильно:** yield = пауза внутри генератора, не во всём приложении.

**Неправильно:** Забывать, что генератор — итератор

**Почему:** Генератор возвращает объект с методом next() и Symbol.iterator.

**Правильно:** Генератор = итератор по умолчанию. Можно использовать в for...of.


Важно запомнить

  • function* создаёт генератор
  • yield — точка приостановки и возврат значения
  • next() возобновляет выполнение
  • Генератор = итератор (Symbol.iterator)
  • yield* делегирует другой итератор

Связь

Назад: Вы знаете перебираемые значения (JI19) и функции (J9). Генераторы объединяют оба понятия.

Вперёд: Следующий урок (JV9) — асинхронные генераторы — сочетание генераторов с Promise.


Читайте дальше

Материалы курса JS Advanced — PROlab Academy.