yield – дорога в обе стороны
До этого генераторы наиболее напоминали «итераторы на стероидах». Но, как мы сейчас увидим, это не так, есть фундаментальное различие, генераторы гораздо мощнее и гибче.
Всё дело в том, что yield – дорога в обе стороны: он не только возвращает результат наружу, но и может передавать значение извне в генератор. Вызов let result = yield value делает следующее:
Возвращает value во внешний код, приостанавливая выполнение генератора.
Внешний код может обработать значение, и затем вызвать next с аргументом: generator.next(arg) .
Генератор продолжит выполнение, аргумент next будет возвращён как результат yield (и записан в result ).
Продемонстрируем это на примере:
function* gen() {
// Передать вопрос во внешний код и подождать ответа
let result = yield "2 + 2?";
alert(result);
}
let generator = gen();
let question = generator.next().value;
// "2 + 2?"
setTimeout(() => generator.next(4), 2000);
На рисунке ниже прямоугольником изображён генератор, а вокруг него – «внешний код», который с ним взаимодействует:
На этой иллюстрации показано то, что происходит в генераторе:
Первый вызов generator.next() – всегда без аргумента, он начинает выполнение и возвращает результат первого yield («2+2?»)`. На этой точке генератор приостанавливает выполнение.
Результат yield переходит во внешний код (в question ). Внешний код может выполнять любые асинхронные задачи, генератор стоит «на паузе».
Когда асинхронные задачи готовы, внешний код вызывает generator.next(4) с аргументом. Выполнение генератора возобновляется, а 4 выходит из присваивания как результат let result = yield ... .
В примере выше – только два next .
Увеличим их количество, чтобы стал более понятен общий поток выполнения:
function* gen() {
let ask1 = yield "Сколько будет 2 + 2?"; alert(ask1); // 4
let ask2 = yield "3 * 3?"
alert(ask2); // 9
}
let generator = gen();
alert( generator.next().value ); // "2 + 2?" alert( generator.next(4).value ); // "3 * 3?" alert( generator.next(9).done ); // true
Взаимодействие с внешним кодом:
Первый .next() начинает выполнение… Оно доходит до первого yield .
Результат возвращается во внешний код.
Второй .next(4) передаёт 4 обратно в генератор как результат первого yield и возобновляет выполнение.
…Оно доходит до второго yield , который станет результатом .next(4) .
Третий next(9) передаёт 9 в генератор как результат второго yield и возобновляет выполнение, которое завершается окончанием функции, так что done: true .
Получается «пинг‑понг»: каждый next(value) передаёт в генератор значение, которое становится результатом текущего yield , возобновляет выполнение и получает выражение из следующего yield . Исключением является первый вызов next , который не может передать значение в генератор, т.к. ещё не было ни одного yield .
Do'stlaringiz bilan baham: |