Этот вопрос проверяет глубокое понимание асинхронной модели выполнения JavaScript, механизма event loop и управления задачами в однопоточном окружении.
Event Loop - это механизм, который позволяет JavaScript обрабатывать асинхронные операции в однопоточном окружении. Он постоянно проверяет очередь задач и выполняет их по порядку. Сначала выполняются все синхронные задачи из call stack, затем микрозадачи (promises), затем макрозадачи (setTimeout, события). Этот цикл обеспечивает неблокирующее выполнение кода.
LIFO-структура (последний вошел - первый вышел)
Хранит выполняемые функции
Один поток выполнения - одна операция в момент времени
javascript
function first() {
second();
console.log('First');
}
function second() {
console.log('Second');
}
first(); // Call stack: first -> second -> console.logFIFO-структура (первый вошел - первый вышел)
Хранит готовые к выполнению асинхронные колбэки
Макрозадачи: setTimeout, setInterval, UI events
Приоритет над callback queue
Хранит микрозадачи: Promise then/catch/finally, queueMicrotask
Выполняется полностью после каждого макрозадания
Выполнить синхронный код из call stack
Проверить очередь микрозадач - выполнить все до опустошения
Выполнить одну макрозадачу из callback queue
Повторить с шага 2
javascript
console.log('Start'); // 1. Синхронный код
setTimeout(() => {
console.log('Timeout'); // 4. Макрозадача
}, 0);
Promise.resolve().then(() => {
console.log('Promise'); // 3. Микрозадача
});
console.log('End'); // 2. Синхронный код
// Результат: Start, End, Promise, Timeoutjavascript
// 1. Синхронная фаза
console.log('Script start');
setTimeout(function timeout1() {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(function promise1() {
console.log('Promise 1');
});
setTimeout(function timeout2() {
console.log('Timeout 2');
Promise.resolve().then(function promise2() {
console.log('Promise 2');
});
}, 0);
console.log('Script end');
/*
Порядок выполнения:
1. Script start
2. Script end
3. Promise 1 (микрозадача)
4. Timeout 1 (макрозадача)
5. Timeout 2 (макрозадача)
6. Promise 2 (микрозадача внутри макрозадачи)
*/Promise callbacks (.then, .catch, .finally)
queueMicrotask()
MutationObserver (в браузере)
process.nextTick (в Node.js)
setTimeout, setInterval
setImmediate (Node.js)
I/O операции
UI rendering (браузер)
События (click, load и т.д.)
Несколько очередей для разных типов событий
Render steps - обновление UI между задачами
RequestAnimationFrame - синхронизация с кадрами анимации
Несколько фаз event loop: timers, pending callbacks, idle/prepare, poll, check, close
process.nextTick - отдельная очередь с высшим приоритетом
setImmediate - выполнение после фазы poll
javascript
// Плохо - блокирует event loop
function heavyCalculation() {
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += Math.sqrt(i);
}
return result;
}
// Лучше - разбить на части
async function nonBlockingCalculation() {
let result = 0;
const chunkSize = 1000000;
for (let i = 0; i < 1000000000; i += chunkSize) {
// Позволяет event loop обрабатывать другие задачи
await new Promise(resolve => setTimeout(resolve, 0));
for (let j = i; j < i + chunkSize; j++) {
result += Math.sqrt(j);
}
}
return result;
}Разбивайте тяжелые вычисления на части
Используйте Web Workers для CPU-intensive задач
Применяйте асинхронные операции для I/O
Минимизируйте синхронные операции в циклах
javascript
// Эффективное создание микрозадач
async function processData(data) {
// Используйте queueMicrotask для приоритетных задач
queueMicrotask(() => {
console.log('High priority task');
});
// Promise для обычных асинхронных операций
return await fetch('/api/process', {
method: 'POST',
body: JSON.stringify(data)
});
}Вывод: Понимание Event Loop критически важно для написания эффективного и отзывчивого JavaScript-кода. Используйте асинхронные операции для предотвращения блокировки и правильно распределяйте задачи между очередями.
Frontend developer
Ментор по Frontend
Полное сопровождение до оффера — без дорогих курсов, с оплатой после трудоустройства
Записаться на консультацию