В этом руководстве вы узнаете о Call Stack — стеке вызовов JavaScript, который представляет собой механизм для отслеживания вызовов функций.
Движок JavaScript использует Call Stack для управления контекстами выполнения: глобальным контекстом выполнения и контекстами выполнения функций.
Он работает по принципу LIFO, т. е. по принципу «последним пришел – первым обслужен».
Когда вы выполняете сценарий, механизм JavaScript создает глобальный контекст выполнения и помещает его в верхнюю часть стека вызовов.
Всякий раз, когда вызывается функция, механизм JavaScript создает контекст выполнения функции, помещает его в начало Call Stack и начинает выполнять функцию.
Если функция вызывает другую функцию, механизм JavaScript создает новый контекст выполнения функции для вызываемой функции и помещает ее на вершину стека вызовов.
Когда текущая функция завершается, механизм JavaScript извлекает ее из стека вызовов и возобновляет выполнение с того места, где оно было остановлено.
Скрипт остановится, когда Call Stack станет пустым.
Пример
Начнем со следующего примера:
function add(a, b) { return a + b; } function average(a, b) { return add(a, b) / 2; } let x = average(10, 20);
Когда механизм JavaScript выполняет этот сценарий, он помещает глобальный контекст выполнения(обозначаемый функцией main()
или global()
) в стек вызовов.
Глобальный контекст выполнения входит в фазу создания и переходит в фазу выполнения.
Движок JavaScript выполняет вызов функции average(10, 20)
, создает контекст выполнения функции для функции average()
и помещает ее на вершину стека вызовов:
Движок JavaScript начинает выполнять функцию medium average()
, поскольку функция average()
находится на вершине стека вызовов.
Функция average()
вызывает функцию add()
. В этот момент движок JavaScript создает еще один контекст выполнения функции для функции add()
и помещает ее на вершину стека вызовов:
Движок JavaScript выполняет функцию add()
и извлекает ее из стека вызовов:
В этот момент функция average()
находится на вершине стека вызовов, движок JavaScript выполняет ее и извлекает из стека.
Теперь стек вызовов пуст, поэтому скрипт перестает выполняться:
На следующем рисунке показано общее состояние стека вызовов на всех этапах:
Переполнение стека
Стек вызовов имеет фиксированный размер, зависящий от реализации хост-среды, будь то веб-браузер или Node.js.
Если количество контекстов выполнения превышает размер стека, возникает ошибка переполнения.
Например, когда вы выполняете рекурсивную функцию, не имеющую условия выхода, движок JavaScript выдаст ошибку переполнения стека:
function fn() { fn(); } fn(); // stack overflow
Асинхронный JavaScript
JavaScript — это однопоточный язык программирования. Это означает, что движок JavaScript имеет только один стек вызовов. Следовательно, он может делать только одну вещь за раз.
При выполнении скрипта движок JavaScript выполняет код сверху вниз, строка за строкой. Другими словами, синхронно.
Асинхронность означает, что механизм JavaScript может выполнять другие задачи, ожидая завершения другой задачи. Например, движок JavaScript может:
- Запросить данные с удаленного сервера.
- Показать счетчик
- Когда данные будут доступны, отобразить их на веб-странице.
Для этого движок JavaScript использует цикл событий, который будет рассмотрен в следующем руководстве.
Заключение
- Механизм JavaScript использует Call Stack для управления контекстами выполнения.
- Стек вызовов использует структуру данных стека, которая работает по принципу LIFO (последним пришел — первым обслужен).