Skip to main content

Що таке генератор (function*)?

Що таке генератор (function*)

Генератор - це функція, яка може призупиняти своє виконання і повертати проміжні значення, а потім продовжувати роботу з того самого місця.

Формально:

function* повертає спеціальний об'єкт - ітератор, який керує виконанням функції.


Як оголошується генератор

javascript
function* myGenerator() { yield 1; yield 2; yield 3; }

При виклику myGenerator() не виконується сам код функції! Вона повертає ітератор, який потрібно "прокручувати" вручну:

javascript
const gen = myGenerator(); 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 призупиняє виконання і повертає значення.


Що робить yield

Оператор yield:

  1. Призупиняє виконання функції;
  2. Повертає значення назовні (у .next());
  3. Дозволяє передати значення назад усередину при наступному виклику .next().

Приклад 1 - проста послідовність:

javascript
function* counter() { yield 1; yield 2; yield 3; } const gen = counter(); 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 }

Приклад 2 - паузи між кроками

javascript
function* steps() { console.log("Крок 1"); yield; console.log("Крок 2"); yield; console.log("Крок 3"); } const gen = steps(); gen.next(); // "Крок 1" gen.next(); // "Крок 2" gen.next(); // "Крок 3"

Тут yield використовується без значення - просто як "точка зупинки".


Як передати значення назад у генератор

Коли ти викликаєш gen.next(value), це value потрапляє всередину генератора, у те місце, де він був призупинений yield.

Приклад 3 - передача значення назад

javascript
function* dialog() { const name = yield "Як тебе звати?"; const age = yield `Привіт, ${name}! Скільки тобі років?`; yield `Тобі ${age} років.`; } const gen = dialog(); console.log(gen.next()); // { value: "Як тебе звати?", done: false } console.log(gen.next("Oleh")); // { value: "Привіт, Oleh! Скільки тобі років?", done: false } console.log(gen.next(25)); // { value: "Тобі 25 років.", done: false } console.log(gen.next()); // { value: undefined, done: true }

Пояснення:

  • Перший next() запускає генератор і повертає перший yield.
  • Другий next("Oleh") вставляє значення "Oleh" у місце, де стояв перший yield.
  • Третій next(25) вставляє 25 у місце другого yield.

Приклад 4 - генератор з нескінченною послідовністю

javascript
function* infinite() { let i = 0; while (true) { yield i++; } } const gen = infinite(); console.log(gen.next().value); // 0 console.log(gen.next().value); // 1 console.log(gen.next().value); // 2

Генератори ідеально підходять для лінивих обчислень - коли тобі потрібно "порційно" видавати дані без створення величезних масивів.


Керування генератором

МетодЩо робить
.next(value)Продовжує виконання й повертає наступний { value, done }
.return(value)Примусово завершує генератор, повертає { value, done: true }
.throw(error)Кидає виняток усередину генератора, який можна спіймати всередині try...catch

Приклад 5 - return() і throw()

javascript
function* process() { try { yield "Крок 1"; yield "Крок 2"; } catch (e) { console.log("Помилка:", e.message); } finally { console.log("Генератор завершено"); } } const gen = process(); console.log(gen.next()); // { value: "Крок 1", done: false } console.log(gen.throw(new Error("Щось пішло не так"))); // Помилка: Щось пішло не так // Генератор завершено

Генератори - це ітератори

Генератор автоматично реалізує інтерфейс ітератора (next()) і ітерованого об'єкта ([Symbol.iterator]).

javascript
function* numbers() { yield 1; yield 2; yield 3; } for (const n of numbers()) { console.log(n); // 1, 2, 3 }

Генератори та асинхронність (бонус)

До появи async/await генератори використовували для асинхронного коду (через бібліотеки на кшталт co).

javascript
function* getData() { const user = yield fetch('/user'); const posts = yield fetch(`/posts?user=${user.id}`); return posts; }

Пізніше на їхній основі й з'явився async/await (по суті, "автоматизовані генератори").


Підсумок

ПоняттяОпис
function*Оголошення генератора
yieldПризупиняє виконання й повертає значення
.next(value)Відновлює виконання, передаючи value всередину
.return(value)Завершує генератор
.throw(error)Кидає виняток у генератор
ГенераторОб'єкт-ітератор, який можна призупиняти й продовжувати

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.