В каком порядке выполнятся таймеры и цепочка then внутри execute?

Задача на Event Loop: синхронный исполнитель Promise, три таймера и две микрозадачи then. Разбираем вывод после вызова execute в браузере.

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

Что ответить на собеседовании

Само объявление execute ничего не печатает. После execute() в браузере вывод будет: 1, Promise, 4, timeOut, 777, then1, then2, timeOut2. Исполнитель Promise синхронный; после таймера с resolve() обе реакции then выполняются как микрозадачи до перехода к следующему таймеру.

Подробный разбор

Ответ с пояснениями

Условие

В каком порядке появятся сообщения при вызове этой функции в браузере?

const execute = () => {
    setTimeout(() => console.log('timeOut'), 0);
    console.log(1);
    new Promise((resolve) => {
        console.log('Promise');
        setTimeout(() => {
            console.log('777');
            resolve();
        }, 0);
    })
        .then(() => console.log('then1'))
        .then(() => console.log('then2'));
    console.log(4);
    setTimeout(() => console.log('timeOut2'), 0);
};

Одно объявление функции ничего не выводит. В условии подразумевается последующий вызов execute().

Результат вызова

1
Promise
4
timeOut
777
then1
then2
timeOut2

Пошаговый разбор

  1. Регистрируется первый таймер. Он не прерывает текущий синхронный код.
  2. Печатается 1. Исполнитель new Promise вызывается немедленно: появляется Promise и регистрируется второй таймер. Промис пока не выполнен.
  3. Цепочка .then подписывается на результат, но её обработчики ещё не запускаются. Печатается 4 и регистрируется третий таймер.
  4. Первый таймер выводит timeOut.
  5. Второй таймер выводит 777 и вызывает resolve(). Реакция первого .then попадает в очередь микрозадач.
  6. На контрольной точке микрозадач выполняется первый обработчик и печатает then1. Его завершение разрешает следующий промис в цепочке, поэтому добавляется и выполняется микрозадача с then2. Очередь очищается до следующей задачи таймера.
  7. Третий таймер печатает timeOut2.

Что важно не перепутать

setTimeout(..., 0) означает планирование задачи, а не немедленный вызов. new Promise сам по себе не переносит свой исполнитель в фон. В этой задаче оба then выполняются между вторым и третьим таймерами, а не после всех таймеров.

Вывод относится к приведённому фрагменту без другого вмешивающегося кода и к браузерному Event Loop. Нулевая задержка не обещает точное время в миллисекундах. Для обсуждения другой среды, например Node.js с дополнительными очередями, сначала нужно зафиксировать её условия. Правила браузерных таймеров описаны в HTML Standard.

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку