Що таке генератор (function*)?
Що таке генератор (function*)
Генератор - це функція, яка може призупиняти своє виконання і повертати проміжні значення, а потім продовжувати роботу з того самого місця.
Формально:
function*повертає спеціальний об'єкт - ітератор, який керує виконанням функції.
Як оголошується генератор
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}При виклику myGenerator() не виконується сам код функції!
Вона повертає ітератор, який потрібно "прокручувати" вручну:
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:
- Призупиняє виконання функції;
- Повертає значення назовні (у
.next()); - Дозволяє передати значення назад усередину при наступному виклику
.next().
Приклад 1 - проста послідовність:
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 - паузи між кроками
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 - передача значення назад
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 - генератор з нескінченною послідовністю
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()
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]).
function* numbers() {
yield 1;
yield 2;
yield 3;
}
for (const n of numbers()) {
console.log(n); // 1, 2, 3
}Генератори та асинхронність (бонус)
До появи async/await генератори використовували для асинхронного коду (через бібліотеки на кшталт co).
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) | Кидає виняток у генератор |
| Генератор | Об'єкт-ітератор, який можна призупиняти й продовжувати |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.