JavaScript — это однопоточный язык программирования, что означает, что он имеет один стек вызовов. Поэтому он может делать что-то одно за раз.

Что такое стек вызовов?

Стек вызовов организован как «стек» — структура данных в памяти для хранения элементов по принципу «последним пришел — первым обслужен» (LIFO), так что вызывающая сторона подпрограммы помещает адрес возврата в стек, а вызываемая подпрограмма после заканчивая, извлекает адрес возврата из стека вызовов, чтобы передать управление этому адресу.

Фрейм стека!? где это существует?

Кадр стека существует только во время выполнения функции, как и объекты в фрейме стека. Преимущество этого заключается в том, что нам не нужно беспокоиться об утечках памяти, вызванных объектами, размещенными в стеке, но объекты также больше не доступны, когда мы возвращаемся из функции.

Что хранится во фрейме стека?

Что на самом деле находится во фрейме стека метода?

Фрейм стека обычно хранит:

  • Локальные переменные
  • Аргументы, переданные в метод
  • Информация о кадре стека вызывающей стороны
  • адрес возврата — что программа должна делать после возврата из функции (т. е. куда она должна «вернуться»). Обычно это где-то в середине кода вызывающей стороны.

Может быть, вы спросите себя: почему в Javascript есть стек вызовов?

Javascript использует стек вызовов в качестве механизма для интерпретатора, например (интерпретатор Javascript в веб-браузере), чтобы отслеживать свое место в сценарии, который выполняет все несколько функций: «какая функция выполняется в данный момент и какая функция вызывается изнутри». вызывается из этой функции и т. д.

Хорошо! Но обязательно ли иметь стек вызовов в Javascript?

Хороший вопрос! Стек вызовов становится необходимым, когда перед браузерами ставится задача выполнять функции, которые имеют либо обратные вызовы, либо рекурсивные вызовы самих себя в рамках их определения функции. Стек вызовов помогает управлять вызовами функций и временно сохраняет информацию о функции в памяти до тех пор, пока она не будет полностью выполнена.

Я проиллюстрирую приведенное выше объяснение примером, показывающим вывод следующего вызова функции вместе со стеком вызовов:

В приведенном выше примере браузер будет читать три определения функций сверху вниз, начиная с первой строки и заканчивая тринадцатой строкой, однако он ничего не сделает, потому что в javascript функция должна быть вызвана, чтобы она могла быть выполнена. выполнить код внутри его фигурных скобок. Как только интерпретатор достигает пятнадцатой строки и видит вызов функции, функция, называемая «третьей функцией», временно сохраняется в структуре, называемой стеком вызовов, вместе с ее переменными и блоком кода.

Внутри «третьей функции» есть вызов «первой функции», который добавит этот вызов выше «третьей функции» в стек вызовов и, таким образом, назначит приоритет выполнения «первой функции». Внутри «firstFunction» есть вызов «secondFunction», который затем добавит secondFunction над «firstFunction» в стек вызовов и назначит приоритет выполнения «secondFunction». Эти приоритеты для выполнения возникают потому, что структура стека вызовов следует правилу, согласно которому последнее добавление в стек будет выполнено первым.

Проследив цепочку вызовов, мы видим, что внутри «secondFunction» есть console.log, который стек вызовов позаботится о том, чтобы выполнить его первым. После полного разрешения вызова secondFunction структура стека вызовов отбрасывает вызов «secondFunction» и перемещается вниз по списку стеков, пока не будет разрешено все вызванное.

Все ли языки программирования используют стек вызовов?

Так что нет, не все языки используют стек вызовов одинаково. Однако большинство языков обрабатывают стек вызовов одинаково: всякий раз, когда вызывается функция, они помещают адрес возврата вместе с любыми аргументами. Затем они вызывают функцию, получают результат (если есть) и возвращаются к адресу возврата в стеке вызовов.

ПОДОЖДИТЕ!!, я писал свой код и вдруг получил это сообщение об ошибке:

Я сломал свою машину!?

Пожалуйста, не паникуйте!. будучи будущим разработчиком, у вас будут тесные отношения между вами и Errors, так что расслабьтесь.

RangeError или StackOverflowError — это ошибка времени выполнения, при которой превышен объем памяти стека вызовов, выделенный браузером. Когда стек вызовов превышается из-за чрезмерной, глубокой или бесконечной рекурсии, отображается RangeError или StackOverflowError.

Если вы когда-нибудь обнаружите, что застряли с ошибкой, подобной этой выше, попробуйте просмотреть свои рекурсивные функции и проверить, нет ли где-нибудь в вашем коде точки останова, которая отключила бы вас от любых рекурсивных вызовов. Эта ошибка аналогична циклу while, который выполняется с условным оператором, который никогда не равняется ложному, AKA. бесконечный цикл.

Если вы когда-нибудь обнаружите, что код содержит ошибки, проверьте свои предположения. Открытие кода с помощью отладчика с помощью инструментов разработчика в вашем браузере даст вам доступ к стеку вызовов вашей программы на вкладке источников. Здесь вы можете сделать паузу и посмотреть, какие вызовы функций стоят в очереди в стеке вызовов вашего браузера, что может пролить свет на любые неприятности, скрытые за несколькими вызовами функций.

Использованная литература: