Проверяет понимание микротасок, рекурсии в промисах и того, как асинхронный код влияет на блокировку главного потока браузера.
Промисы в JavaScript выполняются через механизм микротасок. Когда промис резолвится, его обработчик (например, в .then) не выполняется сразу — он ставится в очередь микротасок. Event loop обрабатывает все микротаски до конца, прежде чем перейти к следующей макротаске (например, рендерингу или обработке события).
Если внутри обработчика промиса снова создаётся и резолвится промис, чей обработчик снова вызывает себя, то каждая итерация добавляет новую микротаску. Очередь микротасок не опустошается, и event loop застревает в цикле обработки микротасок. Это не переполнение стека (как при синхронной рекурсии), потому что каждый вызов происходит в отдельной микротаске, но это бесконечный цикл на уровне event loop.
function loop() {
Promise.resolve().then(loop);
}
loop();
// Страница зависнет: микротаски выполняются бесконечно,
// рендеринг и обработка событий не происходят.
Браузер не может прервать выполнение микротасок, чтобы отрисовать кадр или обработать клик. Пока очередь микротасок не пуста, главный поток занят. В отличие от синхронного while(true), здесь нет переполнения стека, но эффект для пользователя тот же — страница не отвечает.
setTimeout или setInterval для разрыва цепочки микротасок и передачи управления event loop.queueMicrotask осознанно, понимая разницу с макротасками.function loop(n) {
if (n <= 0) return;
Promise.resolve().then(() => loop(n - 1));
}
loop(1000); // завершится, не блокируя страницу навсегда
Итог: рекурсия в обработчике промиса не даёт переполнения стека, но при отсутствии условия выхода приводит к бесконечной обработке микротасок и зависанию страницы. Применяйте такой подход только с явным ограничением глубины или разрывайте цепочку макротасками.
Frontend developer
Ментор по Frontend
Полное сопровождение до оффера — без дорогих курсов, с оплатой после трудоустройства
Записаться на консультацию