Генератори
функція-генератор (generator function) - це особливий тип функції в JavaScript, яка може призупиняти своє виконання і потім продовжувати його з того самого місця.
Це дуже потужний інструмент - вона дозволяє писати ітератори, ліниві обчислення, асинхронні цикли і багато іншого. Розберемося по кроках.
1. Визначення
Функція-генератор - це функція, яка повертає об'єкт-генератор (ітератор), а всередині себе використовує ключове слово
yield, щоб призупиняти виконання і повертати значення по одному.
2. Синтаксис
function* name([args]) {
// тіло функції
}*післяfunctionробить функцію генератором;yieldвикористовується для "покрокової" видачі значень;- при виклику вона не виконується одразу, а повертає генератор (ітератор).
3. Приклад - базовий генератор
function* gen() {
yield 1;
yield 2;
yield 3;
}
const iterator = gen();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }Що відбувається:
- при першому виклику
next()- виконання доходить до першогоyield, повертає 1 і "замерзає"; - при наступному
next()виконання продовжується з того самого місця; - після останнього
yieldгенератор завершує роботу (done: true).
4. Генератори - це ітератори
Генератор повертає об'єкт, сумісний із протоколом ітераторів.
Отже, його можна використовувати в for...of:
function* numbers() {
yield 10;
yield 20;
yield 30;
}
for (const n of numbers()) {
console.log(n);
}Вивід:
10
20
305. Приклад - нескінченний генератор
Генератори можуть бути нескінченними - вони не створюють весь масив одразу, а видають значення "за запитом".
function* infiniteCounter() {
let i = 1;
while (true) {
yield i++;
}
}
const counter = infiniteCounter();
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2
console.log(counter.next().value); // 3
// ...і так нескінченноЦе приклад лінивих обчислень - значення генеруються в міру необхідності.
6. Передача значень у генератор
Можна передавати дані назад у генератор через next(value).
function* dialog() {
const name = yield 'Як тебе звати?';
yield `Привіт, ${name}!`;
}
const it = dialog();
console.log(it.next().value); // "Як тебе звати?"
console.log(it.next('Тим').value); // "Привіт, Тим!"Перший next() запускає генератор,
другий - передає 'Тим' всередину як результат виразу yield.
7. Використання з return
Можна завершити генератор раніше за допомогою return:
function* example() {
yield 1;
return 'кінець';
yield 2; // не виконається
}
const it = example();
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 'кінець', done: true }8. Асинхронні генератори (ES2018)
Асинхронні генератори дозволяють працювати з await всередині ітерованих потоків даних.
async function* fetchData() {
yield await Promise.resolve('Перша частина');
yield await Promise.resolve('Друга частина');
}
for await (const part of fetchData()) {
console.log(part);
}Асинхронні генератори використовують for await...of для асинхронного обходу.
9. Навіщо потрібні генератори
| Застосування | Приклад |
|---|---|
| Створення ітераторів | Поелементна генерація даних |
| Ліниві обчислення | Не потрібно зберігати масив цілком |
| Покрокове виконання | Керування потоком виконання |
| Асинхронні пайплайни | Обробка потоків даних без завантаження пам'яті |
| Емуляція корутин | Можливість "зупинити" і "продовжити" код |
10. Приклад - генератор діапазону
function* range(start, end, step = 1) {
for (let i = start; i <= end; i += step) {
yield i;
}
}
for (const num of range(1, 5)) {
console.log(num);
}Вивід:
1
2
3
4
5ПІДСУМОК
| Властивість | Опис |
|---|---|
| Визначення | Функція з function*, що повертає ітератор |
| Повертає | Об'єкт генератора |
| Ключове слово | yield |
| Можна призупиняти виконання | Так |
| Можна передавати значення назад | Так |
| Асинхронна версія | async function* |
| Основне застосування | Ліниві обчислення, ітератори, асинхронні потоки |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.