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

Что такое Call stack?

1.0 Junior🔥 142 комментариев
#JavaScript Core

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

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

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

Call Stack в JavaScript

Call Stack - это структура данных (стек), которая отслеживает выполнение функций в программе. Когда функция вызывается, она добавляется на вершину стека, когда функция завершается, она удаляется из стека.

Как это работает

Call Stack работает по принципу LIFO (Last In, First Out) - последний добавленный элемент первым удаляется:

function first() {
  console.log("first() начало");
  second();
  console.log("first() конец");
}

function second() {
  console.log("second() начало");
  third();
  console.log("second() конец");
}

function third() {
  console.log("third()");
}

first();

Выполнение происходит так:

1. first() добавляется в стек
   Stack: [first]
   
2. second() добавляется в стек
   Stack: [first, second]
   
3. third() добавляется в стек
   Stack: [first, second, third]
   
4. third() завершается, удаляется из стека
   Stack: [first, second]
   
5. second() завершается, удаляется из стека
   Stack: [first]
   
6. first() завершается, удаляется из стека
   Stack: []

Консоль выведет:

first() начало
second() начало
third()
second() конец
first() конец

Stack Overflow - переполнение стека

Если функция вызывает саму себя без условия выхода (бесконечная рекурсия), Call Stack переполняется:

// ОПАСНО! Бесконечная рекурсия
function recursive() {
  recursive(); // Вызывает саму себя
}

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

Визуально это выглядит так:

recursive() - добавляется
recursive() - добавляется
recursive() - добавляется
... (тысячи слоёв)
recursive() - ПЕРЕПОЛНЕНИЕ!
RangeError!

Правильная рекурсия (с условием выхода)

function factorial(n) {
  // Условие выхода (базовый случай)
  if (n === 1) {
    return 1;
  }
  
  // Рекурсивный вызов
  return n * factorial(n - 1);
}

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

Когда вызвать factorial(5):

Stack: [factorial(5)]
Stack: [factorial(5), factorial(4)]
Stack: [factorial(5), factorial(4), factorial(3)]
Stack: [factorial(5), factorial(4), factorial(3), factorial(2)]
Stack: [factorial(5), factorial(4), factorial(3), factorial(2), factorial(1)]
// factorial(1) возвращает 1, удаляется
Stack: [factorial(5), factorial(4), factorial(3), factorial(2)]
// Вычисляется 2 * 1 = 2
Stack: [factorial(5), factorial(4), factorial(3)]
// И так далее...

Call Stack в DevTools

Вы можете увидеть Call Stack в браузерных DevTools:

function handleClick() {
  processData();
}

function processData() {
  validateInput(); // Поставьте breakpoint здесь
}

function validateInput() {
  debugger; // DevTools остановит выполнение
}

В DevTools -> Sources -> Debugger вы увидите стек вызовов:

Call Stack:
├─ validateInput()
├─ processData()
├─ handleClick()
├─ addEventListener callback
└─ Global

Асинхронный код и Event Loop

Важно понимать, что Call Stack работает только для синхронного кода. Асинхронные операции (setTimeout, fetch, Promise) обрабатываются иначе:

console.log("Начало");

setTimeout(() => {
  console.log("Через 0 мс");
}, 0);

console.log("Конец");

Выведет:

Начало
Конец
Через 0 мс

Почему? Потому что setTimeout не блокирует Call Stack - он отправляет callback в очередь (Task Queue), и она выполняется только когда стек полностью пуст.

Процесс:

1. console.log("Начало") - выполняется, выводит "Начало"
2. setTimeout - отправляет callback в очередь, НЕ добавляет в Call Stack
3. console.log("Конец") - выполняется, выводит "Конец"
4. Call Stack пуст, Event Loop берет callback из очереди
5. Callback выполняется, выводит "Через 0 мс"

Практический пример: отладка через Call Stack

function calculatePrice(quantity, price) {
  const subtotal = multiply(quantity, price);
  const tax = calculateTax(subtotal);
  return addTax(subtotal, tax);
}

function multiply(a, b) {
  return a * b;
}

function calculateTax(amount) {
  return amount * 0.13;
}

function addTax(subtotal, tax) {
  debugger; // Стоп здесь!
  return subtotal + tax;
}

calculatePrice(10, 100);

В DevTools вы увидите:

Call Stack:
├─ addTax
├─ calculatePrice
└─ Global

Это показывает путь выполнения и помогает найти ошибки.

Зачем это нужно frontend разработчику

  1. Отладка: понимание Call Stack помогает искать ошибки в коде
  2. Performance: вложенные функции занимают место в стеке, глубокая рекурсия может замедлить код
  3. Понимание async/await: нужно знать разницу между синхронным Call Stack и асинхронным Event Loop
  4. Поиск утечек памяти: Call Stack может содержать ссылки на объекты, которые не убираются из памяти

Итоги

  • Call Stack отслеживает выполнение функций по принципу LIFO
  • Функция добавляется в стек при вызове, удаляется при завершении
  • Stack Overflow происходит при бесконечной рекурсии
  • DevTools позволяет видеть и отлаживать Call Stack
  • Event Loop обрабатывает асинхронный код отдельно от Call Stack
  • Понимание Call Stack - критически важно для отладки сложных приложений
Что такое Call stack? | PrepBro