Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

Документы

Медиа

Назад
Вопрос про JavaScript: generators, yield, async, await, coroutines, event loop

Почему асинхронность работает через генераторы и yield?

Вопрос проверяет понимание механизма работы асинхронности в JavaScript на низком уровне через генераторы и ключевое слово yield, что необходимо для глубокого понимания работы async/await.

Короткий ответ

Генераторы — это функции, которые можно приостанавливать и возобновлять, используя ключевое слово yield. Эта возможность позволяет реализовать асинхронность, так как можно приостановить выполнение функции, дождаться завершения асинхронной операции (например, запроса к серверу), а затем возобновить выполнение с полученным результатом. Именно так под капотом работают async/await: они преобразуются в код с генераторами и промисами, создавая иллюзию синхронного выполнения асинхронного кода. Это делает код более читаемым и управляемым по сравнению с цепочками then.

Длинный ответ

Генераторы в JavaScript — это особый вид функций, объявляемых через function*, которые могут приостанавливать своё выполнение с помощью ключевого слова yield и возобновлять его позже. Эта пауза не блокирует основной поток, что делает генераторы идеальным инструментом для управления асинхронными операциями. Вместо того чтобы использовать колбэки или цепочки промисов, можно написать код, который выглядит синхронно, но выполняется асинхронно.

Как это работает с асинхронностью?

Представьте, что у вас есть асинхронная задача, например, чтение файла. Вместо того чтобы передавать колбэк, генератор может yield промис, представляющий эту задачу. Внешний "управляющий" код (часто называемый "раннер" или "корутина") получает этот промис, ждёт его разрешения, а затем возобновляет генератор, передавая результат обратно через next(value). Таким образом, генератор приостанавливается на время выполнения асинхронной операции, но поток выполнения не блокируется, и другие задачи могут выполняться.

Практический пример

Рассмотрим простую реализацию асинхронного раннера для генераторов:

function asyncRunner(generatorFunc) {
  const generator = generatorFunc();
  function handle(result) {
    if (result.done) return Promise.resolve(result.value);
    return Promise.resolve(result.value)
      .then(res => handle(generator.next(res)))
      .catch(err => handle(generator.throw(err)));
  }
  return handle(generator.next());
}

// Использование с генератором
asyncRunner(function* fetchData() {
  const response = yield fetch('https://api.example.com/data'); // yield промиса
  const data = yield response.json(); // yield другого промиса
  console.log(data);
  return data;
});

В этом примере asyncRunner принимает функцию-генератор. Каждый раз, когда генератор yield-ит промис, раннер ждёт его разрешения и затем возобновляет генератор с результатом. Код внутри генератора выглядит линейным и синхронным, хотя на самом деле выполняется асинхронно.

Связь с async/await

Ключевые слова async/await, представленные в ES2017, являются синтаксическим сахаром над генераторами и промисами. Под капотом движок JavaScript преобразует async-функцию в генератор, а await — в yield. Это делает код ещё чище, избавляя от необходимости писать явный раннер. Например, предыдущий код можно переписать так:

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  console.log(data);
  return data;
}

Это работает по тому же принципу: функция приостанавливается на каждом await, позволяя выполняться другим задачам, а затем возобновляется с результатом.

Где это применяется?

  • Реализация асинхронных потоков данных (например, с помощью библиотек типа Redux-Saga).
  • Создание пользовательских планировщиков для сложных асинхронных сценариев.
  • Понимание внутреннего устройства современных асинхронных конструкций в JavaScript.

Вывод: Генераторы и yield предоставляют низкоуровневый механизм для реализации асинхронности через приостановку и возобновление выполнения, что лежит в основе более удобного синтаксиса async/await. Этот подход полезен, когда нужно создать кастомные асинхронные паттерны или глубоко понять, как работает асинхронный код в JavaScript.

Уровень

  • Рейтинг:

    3

  • Сложность:

    7

Навыки

  • JavaScript

    JavaScript

Ключевые слова

#generators

#yield

#async

#await

#coroutines

#event loop

Подпишись на Python Developer в телеграм