← Назад к вопросам

Где есть стек в Event Loop?

1.8 Middle🔥 221 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Стек вызовов в Event Loop

Event Loop — это механизм, который управляет выполнением кода в JavaScript. Стек вызовов (Call Stack) является критической частью этого процесса.

Что такое Call Stack (стек вызовов)?

Call Stack — это структура данных, которая отслеживает, какие функции в данный момент выполняются. Она работает по принципу LIFO (Last In, First Out):

function a() {
  console.log('a start');
  b();
  console.log('a end');
}

function b() {
  console.log('b start');
  c();
  console.log('b end');
}

function c() {
  console.log('c');
}

a();

// Порядок выполнения:
// a start
// b start
// c
// b end
// a end

Стек вызовов при выполнении:

1. Global context
2. Global context, a()
3. Global context, a(), b()
4. Global context, a(), b(), c()
5. Global context, a(), b()          <- c() завершена
6. Global context, a()               <- b() завершена
7. Global context                    <- a() завершена

Event Loop архитектура

Event Loop состоит из нескольких компонентов:

  1. Call Stack — стек выполняемого синхронного кода
  2. Callback Queue — очередь асинхронных операций (setTimeout, fetch и т.д.)
  3. Microtask Queue — очередь микротасок (Promises, MutationObserver)
  4. Web APIs — асинхронные операции (XMLHttpRequest, setTimeout, fetch)

Порядок выполнения

console.log('1. Start');

setTimeout(() => {
  console.log('2. setTimeout');
}, 0);

Promise.resolve()
  .then(() => {
    console.log('3. Promise');
  });

console.log('4. End');

// Результат:
// 1. Start
// 4. End
// 3. Promise      <- Microtask Queue выполняется первой
// 2. setTimeout   <- Callback Queue выполняется после Microtask Queue

Как работает Event Loop

// Пример сложной асинхронности

console.log('Script start');

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => {
    console.log('Data:', data);
  });

setTimeout(() => {
  console.log('Timeout 1');
}, 0);

Promise.resolve()
  .then(() => {
    console.log('Promise 1');
  })
  .then(() => {
    console.log('Promise 2');
  });

setTimeout(() => {
  console.log('Timeout 2');
}, 0);

console.log('Script end');

// Порядок выполнения:
// 1. Script start          <- Call Stack
// 2. Script end            <- Call Stack
// 3. Promise 1             <- Microtask Queue
// 4. Promise 2             <- Microtask Queue
// 5. Data: {...}           <- fetch.then (Microtask)
// 6. Timeout 1             <- Callback Queue
// 7. Timeout 2             <- Callback Queue

Визуализация Event Loop

┌──────────────────────────────────────┐
│         JAVASCRIPT ENGINE            │
├──────────────────────────────────────┤
│  Call Stack (синхронный код)         │
│  ┌────────────────────────────────┐  │
│  │  function a()                  │  │
│  │  function b()                  │  │
│  │  console.log()                 │  │
│  └────────────────────────────────┘  │
├──────────────────────────────────────┤
│  Microtask Queue (Promises)          │
│  ┌────────────────────────────────┐  │
│  │ .then()                        │  │
│  │ async/await                    │  │
│  └────────────────────────────────┘  │
├──────────────────────────────────────┤
│  Callback Queue (setTimeout)         │
│  ┌────────────────────────────────┐  │
│  │ setTimeout callback            │  │
│  │ fetch callback                 │  │
│  └────────────────────────────────┘  │
├──────────────────────────────────────┤
│  Web APIs (асинхронные операции)    │
└──────────────────────────────────────┘

Stack Overflow

Если стек растёт бесконечно, происходит Stack Overflow:

// Рекурсия без базового случая
function infinite() {
  infinite();
}

infinite(); // RangeError: Maximum call stack size exceeded

Правильная рекурсия с базовым случаем:

function factorial(n) {
  if (n === 1) return 1; // Базовый случай
  return n * factorial(n - 1);
}

console.log(factorial(5)); // 120

Практический пример: сложное асинхронное выполнение

async function fetchData() {
  console.log('1. Fetch started');
  
  const response = await fetch('https://api.example.com/data');
  console.log('2. Response received');
  
  const data = await response.json();
  console.log('3. Data parsed');
  
  return data;
}

fetchData();
console.log('4. Main execution');

// Результат:
// 1. Fetch started    <- Call Stack
// 4. Main execution   <- Call Stack (async функция передана в Microtask)
// 2. Response received <- Microtask (await разрешилась)
// 3. Data parsed      <- Microtask (await разрешилась)

Оптимизация Event Loop

// Плохо: блокирует Event Loop
for (let i = 0; i < 1000000; i++) {
  // тяжёлые вычисления
}

// Хорошо: разбить на чанки
function processChunk(startIndex, endIndex) {
  for (let i = startIndex; i < endIndex; i++) {
    // вычисления
  }
  
  if (endIndex < totalItems) {
    setTimeout(() => {
      processChunk(endIndex, endIndex + 100);
    }, 0);
  }
}

processChunk(0, 100);

Основные моменты

  1. Call Stack — часть engine, выполняет синхронный код
  2. Microtask Queue — выполняется после Call Stack, перед Callback Queue
  3. Callback Queue — асинхронные операции (setTimeout, setInterval)
  4. Event Loop — проверяет, пуст ли Call Stack, затем берёт из очередей
  5. Приоритет: Call Stack > Microtask Queue > Callback Queue

Вывод

Call Stack — это ключевой компонент Event Loop, который отслеживает выполнение функций. Понимание взаимодействия между Call Stack, Microtask Queue и Callback Queue критично для написания эффективного асинхронного JavaScript кода.