Event Loop с задержками
Условие
Дан следующий код:
const myPromise = (delay) => new Promise((res) => setTimeout(res, delay));
setTimeout(() => console.log("setTimeout1"), 1000);
myPromise(1000).then(() => console.log("Promise1"));
setTimeout(() => console.log("setTimeout2"), 100);
myPromise(2000).then(() => console.log("Promise2"));
setTimeout(() => console.log("setTimeout3"), 2000);
myPromise(1000).then(() => console.log("Promise3"));
setTimeout(() => console.log("setTimeout4"), 1000);
Определите порядок вывода. Учитывайте реальные задержки таймеров.
Что проверяется
- Понимание реального времени выполнения таймеров
- Приоритет микрозадач при одновременном срабатывании
- Работа с промисами и setTimeout
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Порядок вывода
setTimeout2 // 100 мс
setTimeout1 // 1000 мс
setTimeout4 // 1000 мс
Promise1 // 1000 мс (срабатывает после setTimeout1/4)
Promise3 // 1000 мс (срабатывает после setTimeout1/4)
setTimeout3 // 2000 мс
Promise2 // 2000 мс (срабатывает после setTimeout3)
Объяснение по временной шкале
t = 0 мс: Регистрация всех таймеров
const myPromise = (delay) => new Promise((res) => setTimeout(res, delay));
setTimeout(() => console.log("setTimeout1"), 1000); // Срабатит в 1000мс
myPromise(1000).then(() => console.log("Promise1")); // Срабатит в 1000мс
setTimeout(() => console.log("setTimeout2"), 100); // Срабатит в 100мс
myPromise(2000).then(() => console.log("Promise2")); // Срабатит в 2000мс
setTimeout(() => console.log("setTimeout3"), 2000); // Срабатит в 2000мс
myPromise(1000).then(() => console.log("Promise3")); // Срабатит в 1000мс
setTimeout(() => console.log("setTimeout4"), 1000); // Срабатит в 1000мс
Все таймеры добавлены в очередь, но они выполнятся в разное время.
t = 100 мс: Первый setTimeout
Macrotask Queue: setTimeout2 Event Loop: Выполняем setTimeout2 → Выводит: setTimeout2 Microtask Queue: Пусто
t = 1000 мс: Срабатывают сразу 4 события
В этот момент срабатывают:
- setTimeout для setTimeout1 (задержка 1000мс)
- setTimeout внутри myPromise(1000) для Promise1
- setTimeout для setTimeout4 (задержка 1000мс)
- setTimeout внутри myPromise(1000) для Promise3
Важно: setTimeout1 и setTimeout4 идут в очередь одновременно, так что порядок определяется регистрацией:
Макротаски (упорядочены по регистрации):
1. callback для setTimeout1
2. callback для setTimeout4
Event Loop выполняет:
-
Первая макротаска (setTimeout1 callback) → Выводит: setTimeout1
- Микротаски не добавлены
-
Вторая макротаска (setTimeout4 callback) → Выводит: setTimeout4
- Микротаски не добавлены
После выполнения всех макротасок проверяются микротаски:
- setTimeout из myPromise(1000) разрешил Promise1 → Выводит: Promise1
- setTimeout из myPromise(1000) разрешил Promise3 → Выводит: Promise3
t = 2000 мс: Срабатывают ещё 2 события
В этот момент срабатывают:
- setTimeout для setTimeout3 (задержка 2000мс)
- setTimeout внутри myPromise(2000) для Promise2
Event Loop выполняет:
-
Макротаска (setTimeout3 callback) → Выводит: setTimeout3
-
После выполнения макротаски проверяются микротаски:
- setTimeout из myPromise(2000) разрешил Promise2 → Выводит: Promise2
Полная временная диаграмма
Время Событие Очередь макро Очередь микро Вывод
─────────────────────────────────────────────────────────────────────
0мс Регистрация setTimeout1 ∅ ∅
setTimeout1(1000) setTimeout2 ∅
myPromise(1000) setTimeout3 ∅
setTimeout2(100) setTimeout4 ∅
myPromise(2000)
setTimeout3(2000)
myPromise(1000)
setTimeout4(1000)
100мс setTimeout2 готов setTimeout1 ∅ setTimeout2
Выполняем setTimeout3 ∅
setTimeout4
1000мс setTimeout1 готов setTimeout1 Promise1(микро) setTimeout1
setTimeout4 готов setTimeout4 Promise3(микро)
myPromise1 готов
myPromise3 готов
Выполняем setTimeout1 setTimeout4 Promise1
Promise3
Выполняем setTimeout4 Promise1
Promise3
Выполняем микротаски Promise1 ∅ Promise1
Выполняем микротаски Promise3 Promise3
2000мс setTimeout3 готов ∅ Promise2(микро) setTimeout3
myPromise2 готов
Выполняем setTimeout3 Promise2
Выполняем микротаски Promise2 ∅ Promise2
Ключевые правила
-
Синхронный код: Выполняется первым (все setTimeout, Promise регистрируются)
-
Порядок в очереди Macrotask: FIFO (первый пришёл — первый ушёл)
- setTimeout1 зарегистрирован раньше, чем setTimeout4
- В t=1000мс оба готовы, но setTimeout1 выполнится раньше
-
После каждой Macrotask: Проверяются ВСЕ готовые микротаски
- После setTimeout1 → выполняются Promise1 и Promise3 (если оба готовы)
- После setTimeout3 → выполняется Promise2
-
Задержка таймера: Минимальная, не гарантированная
- setTimeout(0) выполнится в ~4мс минимум
- Фактическое время зависит от CPU load
Почему Promise срабатывает ДЕ после setTimeout?
Потому что внутри myPromise есть setTimeout:
const myPromise = (delay) =>
new Promise((res) =>
setTimeout(res, delay) // setTimeout вызывает resolve
);
Поэтому Promise разрешается только когда внутренний setTimeout срабатывает. А resolve() тогда идёт в Microtask Queue.
Частые неправильные ответы
❌ "Promise выполнится в 1000мс, потом setTimeout1" ✓ Правильно: setTimeout1 выполнится в 1000мс, потом внутренний setTimeout разрешит Promise (микротаска)
❌ "Promise1 и Promise3 выполнятся в начале" ✓ Правильно: они дождутся разрешения своих setTimeout
❌ "setTimeout2 выполнится в конце" ✓ Правильно: setTimeout2 с задержкой 100мс выполнится ПЕРВЫМ