Цикл событий: стек вызовов, очередь и микрозадачи
Разберитесь наглядно, как выполняется JavaScript: изучите стек вызовов, очередь задач и микрозадачи из Promise, а также поймите, почему интерфейс не блокируется во время асинхронных операций.
«Цикл событий: стек вызовов, очередь и микрозадачи» — бесплатный урок Frontend Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Frontend Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Frontend Academy содержит 4 уроков всего.
JavaScript выполняется в одном потоке
JavaScript выполняется в одном потоке — одновременно он может исполнять только один фрагмент кода. И всё же он обрабатывает тысячи асинхронных операций (сетевые запросы, таймеры, события интерфейса), не блокируя выполнение. Как это возможно? Благодаря циклу событий.
Стек вызовов
В стеке вызовов JavaScript отслеживает, какая функция выполняется в данный момент. При вызове функции в стек добавляется кадр. После её возврата кадр удаляется. Если стек переполняется (например, из-за бесконечной рекурсии), возникает переполнение стека.
function c() { /* does something */ }
function b() { c(); }
function a() { b(); }
a();
// Call stack during c():
// c ← top
// b
// a
// (anonymous)Веб-интерфейсы — передача работы
Когда JavaScript вызывает асинхронную функцию (setTimeout, fetch, addEventListener), работа передаётся веб-интерфейсу в браузере. Движок JS продолжает выполнение со следующей строки — он не ждёт.
console.log('1');
setTimeout(() => console.log('2'), 0); // handed to Web API
console.log('3');
// Output: 1, 3, 2Очередь задач (очередь макрозадач)
Когда операция веб-API завершается (срабатывает таймер или завершается fetch), функция обратного вызова помещается в очередь задач (очередь макрозадач). Цикл событий переносит функцию обратного вызова в стек вызовов только тогда, когда стек пуст.
Очередь микрозадач
Промисы используют очередь микрозадач — очередь с высоким приоритетом. После завершения каждой задачи и перед выбором следующей задачи обрабатываются все ожидающие микрозадачи. Микрозадачи всегда выполняются перед следующей макрозадачей.
console.log('1');
setTimeout(() => console.log('timeout'), 0); // macrotask
Promise.resolve().then(() => console.log('promise')); // microtask
console.log('2');
// Output: 1, 2, promise, timeoutЦикл событий в действии
Алгоритм работы цикла событий: 1) выполнять текущую задачу из стека вызовов, пока стек не опустеет; 2) полностью обработать очередь микрозадач; 3) при необходимости выполнить отрисовку; 4) выбрать следующую макрозадачу и повторить действия.
queueMicrotask()
queueMicrotask(fn) планирует функцию обратного вызова в очереди микрозадач, не создавая промис. Напрямую это требуется редко, но полезно понимать, как библиотеки реализуют планирование.
queueMicrotask(() => console.log('microtask'));
console.log('sync');
// Output: sync, microtaskПочему длительные задачи замораживают интерфейс
Если синхронная задача выполняется слишком долго (например, плотный цикл обрабатывает большой объём данных), цикл событий не может обрабатывать события интерфейса или выполнять отрисовку. Страница перестаёт отвечать. Разбивайте длительную работу на части с помощью setTimeout, чтобы передавать управление обратно циклу событий.
// Bad — blocks the UI for seconds:
for (let i = 0; i < 10_000_000; i++) { /* heavy work */ }
// Better — yield periodically:
async function processInChunks(items) {
for (let i = 0; i < items.length; i++) {
process(items[i]);
if (i % 100 === 0) await new Promise(r => setTimeout(r, 0)); // yield
}
}Веб-воркеры — настоящий параллелизм
Для ресурсоёмких задач, использующих CPU, применяйте веб-воркер — отдельный поток со своим циклом событий. Воркеры взаимодействуют с основным потоком через postMessage. Общей памяти нет, поэтому нет и состояний гонки.
requestAnimationFrame
requestAnimationFrame(callback) планирует функцию обратного вызова перед следующей перерисовкой браузера. Используйте его для анимаций, управляемых JavaScript: он синхронизируется с частотой обновления экрана (обычно 60 кадров/с).
function animate(timestamp) {
// update positions based on timestamp
element.style.transform = `translateX(${timestamp * 0.1 % 400}px)`;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);Визуализация цикла событий
Интерактивная демонстрация на latentflip.com/loupe позволяет вставить код и наблюдать за стеком вызовов, веб-API, очередью задач и циклом событий в замедленном режиме. Это незаменимый инструмент для формирования интуитивного понимания.
Быстрая проверка
В какой очереди выполняется функция обратного вызова .then() после выполнения промиса?
Итоги: цикл событий
JavaScript работает в одном потоке. Асинхронная работа передаётся веб-API. Функции обратного вызова возвращаются через очередь задач (обратные вызовы setTimeout и fetch) или очередь микрозадач (промисы). После каждой задачи цикл событий обрабатывает микрозадачи, а затем переходит к следующей отрисовке или макрозадаче. Длительный синхронный код блокирует всё.
Часто задаваемые вопросы
Урок «Цикл событий: стек вызовов, очередь и микрозадачи» бесплатный?
Да — полный текст урока «Цикл событий: стек вызовов, очередь и микрозадачи» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Frontend Academy, подпишись на CoddyKit PRO. Курс Frontend Academy содержит 4 уроков всего.
Чему я научусь в уроке «Цикл событий: стек вызовов, очередь и микрозадачи»?
Разберитесь наглядно, как выполняется JavaScript: изучите стек вызовов, очередь задач и микрозадачи из Promise, а также поймите, почему интерфейс не блокируется во время асинхронных операций. Ты практикуешь Frontend Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Frontend Academy?
Предыдущий опыт не требуется. Frontend Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Цикл событий: стек вызовов, очередь и микрозадачи»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Frontend Academy?
Да. Каждый урок Frontend Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Цикл событий: стек вызовов, очередь и микрозадачи
- Колбэки и ад колбэков
- Promise: then, catch, finally и Promise.all
- async/await и обработка ошибок