← Назад к вопросам
Как происходит обработка очереди событий?
2.0 Middle🔥 181 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Обработка очереди событий в JavaScript
Очередь событий (Event Queue) - это одна из ключевых концепций в JavaScript, которая объясняет асинхронное выполнение кода. Давайте разберемся, как это работает.
Архитектура Event Loop
JavaScript работает на основе Event Loop - это механизм, который постоянно проверяет, есть ли задачи для выполнения.
// Визуализация работы Event Loop:
// 1. Call Stack - стек вызовов функций
// 2. Web APIs - браузерные API (setTimeout, fetch, addEventListener)
// 3. Callback Queue - очередь обратных вызовов
// 4. Event Loop - проверяет когда stack пуст
console.log("1: Начало");
setTimeout(() => {
console.log("2: setTimeout (переходит в callback queue)");
}, 0);
Promise.resolve().then(() => {
console.log("3: Promise (микротаск)");
});
console.log("4: Конец");
// Вывод:
// 1: Начало
// 4: Конец
// 3: Promise (микротаск выполняется раньше макротаска)
// 2: setTimeout
Call Stack (стек вызовов)
Это место, где выполняется синхронный код. JavaScript обрабатывает функции по принципу LIFO (Last In, First Out).
function functionA() {
functionB();
console.log("A finished");
}
function functionB() {
console.log("B executing");
}
functionA();
// Стек:
// 1. functionA() добавляется в стек
// 2. functionB() добавляется в стек (сверху)
// 3. functionB() выполняется и удаляется
// 4. functionA() продолжает и удаляется
Макротаски и Микротаски
Важное различие - есть две очереди: макротаски и микротаски.
console.log("Start");
// Микротаска 1 - Promise
Promise.resolve().then(() => {
console.log("Микротаска 1");
});
// Макротаска 1 - setTimeout
setTimeout(() => {
console.log("Макротаска 1");
// Микротаска 2 - Promise внутри макротаски
Promise.resolve().then(() => {
console.log("Микротаска 2");
});
}, 0);
// Микротаска 3 - Promise
Promise.resolve().then(() => {
console.log("Микротаска 3");
});
console.log("End");
// Вывод:
// Start
// End
// Микротаска 1
// Микротаска 3
// Макротаска 1
// Микротаска 2
Типы макротаск
// Макротаски:
setTimeout(() => {}, 0);
setInterval(() => {}, 0);
requestAnimationFrame(() => {});
element.addEventListener("click", () => {});
Типы микротаск
// Микротаски:
Promise.resolve().then(() => {});
queueMicrotask(() => {});
MutationObserver
Полный цикл Event Loop
// 1. Выполнить весь синхронный код
console.log("1. Синхронный код");
// 2. Проверить микротаски и выполнить все
Promise.resolve().then(() => {
console.log("2. Микротаски");
});
// 3. Выполнить одну макротаску
setTimeout(() => {
console.log("3. Макротаска");
// 4. После макротаски снова проверить микротаски
Promise.resolve().then(() => {
console.log("4. Микротаски после макротаски");
});
}, 0);
Практический пример: оптимизация
// Неправильно - микротаски могут блокировать UI
for (let i = 0; i < 1000000; i++) {
Promise.resolve().then(() => {
// Тяжелое вычисление
});
}
// Правильно - использовать макротаски для разделения нагрузки
function processLargeData() {
for (let i = 0; i < 100; i++) {
setTimeout(() => {
// Обработать 100 элементов
}, 0);
}
}
Важные выводы
- JavaScript - однопоточный язык, но Event Loop делает его асинхронным
- Микротаски выполняются ПЕРЕД следующей макротаской
- После макротаски браузер проверяет микротаски ДО следующей макротаски
- Рендеринг происходит между макротасками (через requestAnimationFrame)
- Понимание Event Loop критично для оптимизации производительности