Вопрос про async/await, который ломает сеньоров | Sobes AI
S.
Sobes AI

Один вопрос про async/await, который ломает мозг даже сеньорам

23.03.2026 | 1 мин чтения | 1 просмотров

70% фронтенд-разработчиков используют async/await каждый день. Но попроси их предсказать порядок вывода в 6 строчках кода — и начинается хаос. Этот вопрос задают в Яндексе, Тинькофф и на каждом втором JavaScript-собесе. И большинство отвечает неправильно.

Вопрос

Вот код. Что выведется в консоль и в каком порядке?

console.log('A');

setTimeout(() => console.log('B'), 0);

Promise.resolve().then(() => console.log('C'));

async function run() {
  console.log('D');
  await Promise.resolve();
  console.log('E');
}

run();

console.log('F');

Засеки 30 секунд. Напиши ответ на бумажке, прежде чем читать дальше.

Почему его задают

Это не вопрос на знание синтаксиса — async/await сейчас напишет любой джун. Интервьюеру нужна твоя ментальная модель event loop.

Без этой модели ты:

  • не поймёшь, почему UI фризится при «асинхронном» коде
  • не отладишь race condition в продакшене
  • не объяснишь, почему один fetch блокирует рендер, хотя «всё же асинхронное»
  • не пройдёшь code review, где коллега спрашивает «а тут точно нет race?»

Синтаксис можно загуглить за 10 секунд. Ментальную модель event loop — нет. Поэтому спрашивают именно её.

Плохой ответ

Типичная ошибка — думать, что async/await делает код «по-настоящему параллельным» или что setTimeout(..., 0) выполнится «сразу после текущей строки».

Плохой ответ: A, B, C, D, E, F. Или A, D, F, E, C, B. Или любая комбинация, собранная по интуиции.

Когда интервьюер просит объяснить — начинается: «ну, setTimeout откладывает... await ждёт... промис выполняется потом...» Это звучит как описание погоды, а не как объяснение механизма. Интервьюер в этот момент уже мысленно ставит «нет».

Правильный ответ

A → D → F → C → E → B

Разберём по шагам.

Синхронная фаза — выполняется всё, что лежит в call stack:

  • console.log('A') — выводит A
  • setTimeout(...) — регистрирует колбэк в очереди макрозадач (Task Queue). Не выполняет — просто ставит в очередь
  • Promise.resolve().then(...) — промис уже resolved, колбэк с console.log('C') уходит в очередь микрозадач (Microtask Queue)
  • Вызов run()console.log('D') — выводит D
  • await Promise.resolve() — промис resolved, но await приостанавливает run(). Всё, что идёт после await, встаёт в очередь микрозадач
  • Управление возвращается в глобальный контекст → console.log('F') — выводит F

Фаза микрозадач — call stack пуст, event loop обрабатывает Microtask Queue:

  • Колбэк промиса → выводит C
  • Продолжение run() после await → выводит E

Фаза макрозадач — микрозадачи закончились, event loop берёт из Task Queue:

  • Колбэк setTimeout → выводит B

Три фазы. Три очереди. Одна модель.

Что на самом деле проверяют

Не async/await. Проверяют три вещи:

1. Call Stack — JavaScript однопоточный. Весь синхронный код выполняется до конца, прежде чем что-либо «асинхронное» получит шанс запуститься. A, D и F выводятся первыми — неважно, что между ними есть setTimeout и промис.

2. Microtask Queue приоритетнее Task Queue. Промисы (и продолжения после await) попадают в очередь микрозадач. setTimeout, setInterval, requestAnimationFrame — в макрозадачи. Микрозадачи всегда обрабатываются первыми. Даже setTimeout(..., 0) подождёт, пока все промисы отработают.

3. await — это не пауза. await не останавливает программу. Он приостанавливает конкретную async-функцию и возвращает управление вызывающему коду. Принципиальное отличие от sleep() в других языках. Именно здесь ломается интуиция бэкендеров, пришедших из Python или Go.

Усложнённая версия

Если базовый вопрос не вызвал проблем, интервьюер добавит вложенные промисы:

Promise.resolve().then(() => {
  console.log('1');
  Promise.resolve().then(() => console.log('2'));
});

Promise.resolve().then(() => console.log('3'));

Ответ: 1 → 3 → 2. Колбэк с console.log('3') уже стоит в очереди микрозадач, когда выполняется первый колбэк. А console.log('2') добавляется в конец очереди внутри первого колбэка — то есть после '3'. Микрозадачи выполняются в порядке добавления, и новые микрозадачи, созданные внутри текущей, встают в конец той же очереди.

Если ты уже знаешь, какие фразы гарантируют отказ на собесе, пора убедиться, что технические ответы тоже не подведут.

Как это тренировать

Не зубри порядок вывода конкретных примеров — задачи каждый раз разные. Тренируй модель: увидел код → разложил на call stack, микрозадачи, макрозадачи → предсказал порядок. Это навык, а не знание.

Попробуй разобрать такие задачи с Sobes AI. Он даст код, выслушает твой ход мыслей и ткнёт в момент, где модель ломается. Лучше сломаться на тренировке, чем на собесе за 400к.

Готовитесь к собеседованию?

Sobes AI слушает вопросы интервьюера и генерирует ответы в реальном времени.

Скачать Sobes AI