Вопрос проверяет понимание взаимосвязи между однопоточным циклом событий JavaScript, блокировкой UI и асинхронными операциями, такими как задачи из очереди микрозадач (microtasks) и макрозадач (macrotasks).
Цикл событий (Event Loop) в JavaScript управляет выполнением кода, сбора событий и обработки очередей задач. Он работает в одном основном потоке, который также отвечает за отрисовку UI. Если этот поток заблокирован долгим синхронным вычислением (например, большим циклом), браузер не может обновлять интерфейс и обрабатывать пользовательский ввод — это и есть блокировка UI.
Во время выполнения синхронного кода цикл событий "заморожен" на текущей задаче. Однако асинхронные операции (например, setTimeout, обработчики событий, разрешённые промисы) продолжают планироваться и помещаться в соответствующие очереди:
.then/.catch/.finally), queueMicrotask(), мутации DOM (в некоторых реализациях).setTimeout, setInterval, события DOM (клики, нажатия клавиш), операции ввода-вывода.Пока основной поток занят, эти задачи не выполняются, но они накапливаются в своих очередях.
Рассмотрим пример, который демонстрирует накопление:
console.log('Start');
// Макрозадача: таймер
setTimeout(() => console.log('Timeout 1'), 0);
// Микрозадача: промис
Promise.resolve().then(() => console.log('Promise 1'));
// Имитация долгой блокировки UI (синхронный цикл)
const start = Date.now();
while (Date.now() - start < 2000) { /* Блокировка на 2 секунды */ }
console.log('End after blocking');
// Ещё одна микрозадача после блокировки
Promise.resolve().then(() => console.log('Promise 2'));Вывод в консоли будет:
Start
End after blocking
Promise 1
Promise 2
Timeout 1Объяснение:
setTimeout помещается в очередь макрозадач, а коллбэк Promise.resolve().then — в очередь микрозадач.Promise 2) помещается в очередь микрозадач.Это знание критично для написания отзывчивых приложений. Долгие синхронные операции (сложные вычисления, синхронные AJAX-запросы) блокируют обработку пользовательских событий и анимации, что приводит к "зависанию" интерфейса. Чтобы избежать этого, тяжёлые задачи следует выносить в Web Workers или разбивать на части с использованием setTimeout/setImmediate или async/await, что позволяет циклу событий периодически обрабатывать другие задачи и обновлять UI.
Итог: Задачи действительно накапливаются в очередях во время блокировки UI. Понимание этого механизма помогает предотвращать проблемы с производительностью, правильно используя асинхронные паттерны и избегая блокировки основного потока.