Обычные генераторы в JavaScript позволяют писать асинхронный код благодаря их способности приостанавливать и возобновлять выполнение, а также передавать значения в обоих направлениях (через yield и next()).
Вот как это работает в контексте асинхронности:
Приостановка выполнения (yield): При достижении оператора yield, генератор приостанавливается и возвращает значение. В асинхронном коде это значение может представлять собой промис или другое "действие", которое нужно выполнить асинхронно.
Ожидание асинхронного результата: Внешний код (например, "раннер" или обертка для генератора) получает значение, переданное через yield. Если это промис, он ждет его разрешения или отклонения.
Возобновление выполнения (next()): После завершения асинхронной операции (разрешения промиса), асинхронный результат (значение промиса) передается обратно в генератор через метод next(). Генератор возобновляет выполнение с точки, где он был приостановлен.
Передача результата: Значение, переданное в next(), становится результатом выражения yield внутри генератора. Таким образом, генератор может "получить" результат асинхронной операции и продолжить работу с ним, как если бы код был синхронным.
Этот паттерн создает иллюзию синхронного выполнения для асинхронных операций, делая код более читаемым и управляемым по сравнению с традиционным использованием колбэков или сложных цепочек .then().
Примером такого использования являются обертки типа co (хотя сейчас более распространены async/await, которые по сути являются синтаксическим сахаром над генераторами и промисами):
javascript
В этом примере yield Promise.resolve(1) приостанавливает генератор. "Раннер" (или co) ждет, пока промис разрешится, и затем возобновляет генератор, передав значение 1 через next(1). Это значение 1 становится результатом yield Promise.resolve(1) внутри генератора, позволяя обработать его на следующей строке (console.log). Этот механизм позволяет имитировать синхронный поток выполнения для асинхронных операций.