Стек вызовов
Посмотрите, как отслеживаются вызовы функций.
«Стек вызовов» — бесплатный урок JavaScript Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения JavaScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс JavaScript Academy содержит 4 уроков всего.
Что такое стек вызовов
Стек вызовов — это механизм, с помощью которого JavaScript отслеживает, какая функция выполняется сейчас и куда нужно вернуть управление. Каждый вызов функции помещается наверх стека, а после завершения снимается.
Это структура LIFO: последним вошёл — первым вышел.
Помещение и снятие со стека
При вызове функции в стек помещается кадр. При возврате кадр снимается. Следите за порядком записей журнала при вложенных вызовах.
function first() {
console.log('first start');
second();
console.log('first end');
}
function second() {
console.log('second');
}
first();LIFO в действии
Функция, вызванная последней, должна завершиться, прежде чем возобновится выполнение функции под ней. Внутренний вызов завершается первым, хотя начался последним.
function a() {
console.log('enter a');
b();
console.log('exit a');
}
function b() {
console.log('enter b');
c();
console.log('exit b');
}
function c() {
console.log('c runs');
}
a();Синхронное выполнение блокирует
JavaScript выполняет только одно действие за раз в одном потоке. Пока стек содержит кадры, ничто другое не выполняется. Синхронный код блокирует выполнение до завершения.
console.log('start');
function busy() {
let sum = 0;
for (let i = 0; i < 1000; i++) sum += i;
return sum;
}
console.log(busy());
console.log('end');Возвращаемые значения идут вниз
Когда каждый кадр снимается, его возвращаемое значение передаётся ожидающему вызывающему коду, расположенному ниже в стеке.
function square(n) {
return n * n;
}
function sumOfSquares(a, b) {
return square(a) + square(b);
}
console.log(sumOfSquares(3, 4));Рекурсия увеличивает стек
Каждый рекурсивный вызов добавляет ещё один кадр. Стек растёт, пока не будет достигнут базовый случай, после чего разматывается кадр за кадром.
function countdown(n) {
if (n === 0) {
console.log('liftoff');
return;
}
console.log(n);
countdown(n - 1);
}
countdown(3);Переполнение стека
Размер стека ограничен. Рекурсия без базового случая продолжает добавлять кадры, пока движок не выдаст RangeError: превышен максимальный размер стека вызовов.
function endless(n) {
return endless(n + 1);
}
try {
endless(1);
} catch (e) {
console.log(e.name);
}Порядок выполнения предсказуем
Поскольку стек работает строго по принципу LIFO, а код выполняется синхронно, порядок синхронных записей журнала всегда предсказуем. Его можно проследить вручную.
function outer() {
console.log(1);
inner();
console.log(3);
}
function inner() {
console.log(2);
}
outer();
console.log(4);Где появляется асинхронность
Стек вызовов выполняет только синхронный код. Функции вроде setTimeout передают работу среде выполнения, которая позже помещает обратные вызовы в очереди. Эти обратные вызовы выполняются только после того, как стек станет пустым.
Так мы подходим к циклу событий.
console.log('A');
setTimeout(() => console.log('B (later)'), 0);
console.log('C');Сначала стек должен очиститься
Даже таймер с нулевой задержкой ждёт завершения всего синхронного кода. Обратный вызов не может выполниться, пока в стеке остаются кадры.
console.log('sync 1');
setTimeout(() => console.log('timeout'), 0);
console.log('sync 2');
console.log('sync 3');Зачем нужен стек вызовов
Понимание стека вызовов объясняет, почему длинные синхронные циклы заставляют страницу зависать, почему рекурсия может привести к переполнению и почему асинхронные обратные вызовы всегда выполняются последними. Это основа всего, что происходит в цикле событий.
function compute() {
return [1, 2, 3].reduce((a, b) => a + b, 0);
}
console.log('before');
console.log(compute());
console.log('after');Быстрая проверка
Какому принципу упорядочивания подчиняется стек вызовов?
Повторение: стек вызовов
Вы изучили основу выполнения в движке:
- Стек вызовов отслеживает выполняющиеся функции в порядке LIFO.
- JavaScript однопоточен, а синхронный код блокирует выполнение.
- Рекурсия увеличивает стек и может привести к его переполнению.
- Асинхронные обратные вызовы ждут, пока стек освободится, что приводит нас к циклу событий.
Часто задаваемые вопросы
Урок «Стек вызовов» бесплатный?
Да — полный текст урока «Стек вызовов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс JavaScript Academy, подпишись на CoddyKit PRO. Курс JavaScript Academy содержит 4 уроков всего.
Чему я научусь в уроке «Стек вызовов»?
Посмотрите, как отслеживаются вызовы функций. Ты практикуешь JavaScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать JavaScript Academy?
Предыдущий опыт не требуется. JavaScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Стек вызовов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке JavaScript Academy?
Да. Каждый урок JavaScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.