Yield у генераторах
1. Що робить yield
yield- це оператор, який повертає значення з функції-генератора назовні і призупиняє виконання до наступного виклику.next().
Тобто:
- коли генератор "доходить" до
yield, він заморожується; - коли ми знову викликаємо
.next(), він відновлює роботу одразу після тогоyield, де зупинився.
2. Найпростіший приклад
function* gen() {
console.log('До першого yield');
yield 1;
console.log('Між yield');
yield 2;
console.log('Після другого yield');
}
const it = gen();
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: undefined, done: true }Що відбувається покроково:
gen()повертає об'єкт-ітератор -> функція ще не запущена.it.next()-> запускає функцію -> доходить доyield 1, повертає{ value: 1 }і заморожується.- Наступний
it.next()-> продовжує з того самого місця, післяyield 1. - Після другого
yieldзнову "заморожується". - Коли
done: true, генератор завершив роботу.
3. Як yield повертає значення
function* seq() {
yield 'A';
yield 'B';
yield 'C';
}
const it = seq();
console.log(it.next().value); // "A"
console.log(it.next().value); // "B"
console.log(it.next().value); // "C"
console.log(it.next().done); // trueyield - це "тимчасовий return":
він повертає значення, але не завершує функцію.
4. Передача значення назад у генератор через next(value)
yield не тільки повертає дані назовні,
а й може приймати значення назад при наступному виклику .next(value).
function* dialog() {
const name = yield 'Як тебе звати?';
yield `Привіт, ${name}!`;
}
const chat = dialog();
console.log(chat.next().value); // "Як тебе звати?"
console.log(chat.next('Tim').value); // "Привіт, Tim!"- Перший
next()запустив генератор і дійшов до першогоyield. - Другий
next('Tim')передав'Tim'у генератор - і це значення потрапило вconst name.
5. Завершення генератора через return
Коли генератор доходить до кінця,
або якщо викликати iterator.return(value),
він завершує виконання з done: true.
function* numbers() {
yield 1;
yield 2;
}
const it = numbers();
console.log(it.next()); // { value: 1, done: false }
console.log(it.return('stop')); // { value: 'stop', done: true }
console.log(it.next()); // { value: undefined, done: true }6. yield* - делегування іншому генератору
Іноді один генератор може "передати керування" іншому через yield*.
function* inner() {
yield 'B';
yield 'C';
}
function* outer() {
yield 'A';
yield* inner(); // передає керування іншому генератору
yield 'D';
}
for (const val of outer()) {
console.log(val);
}Вивід:
A
B
C
Dyield* - це вкладений цикл: "просто yield усі значення іншого генератора".
7. Важливий момент - "лінивість"
yield робить генератори лінивими (lazy) -
значення обчислюються тільки за запитом, а не заздалегідь.
function* range(start, end) {
for (let i = start; i <= end; i++) {
console.log('Генерую', i);
yield i;
}
}
for (const num of range(1, 3)) {
console.log('Отримано:', num);
}Вивід:
Генерую 1
Отримано: 1
Генерую 2
Отримано: 2
Генерую 3
Отримано: 3Генератор "створює" значення в міру потреби, а не зберігає весь діапазон одразу.
8. Помилки всередині генератора (throw)
Можна "закинути" помилку прямо всередину генератора:
function* gen() {
try {
yield 1;
} catch (e) {
console.log('Помилку спіймано:', e.message);
}
}
const it = gen();
it.next();
it.throw(new Error('Щось не так')); // Помилку спіймано: Щось не такПідсумок
| Особливість | Опис |
|---|---|
| Що робить | Призупиняє виконання і повертає значення |
| Відновлення | Через .next() |
| Чи можна передавати значення назад | Так (next(value)) |
| Чи можна завершити | Через return() |
| Чи можна делегувати | Через yield* |
| Обчислення | Ліниві |
| Працює тільки в | function* (генераторах) |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.