Photo by Annie Spratt on Unsplash
What is the JavaScript Call Stack?
According to MDN: A call stack is a mechanism for an interpreter (like the JavaScript interpreter in a web browser) to keep track of its place in a script that calls multiple functions — what function is currently being run and what functions are called from within that function, etc.
At its most basic level, the call stack is where our code is executed, using execution context.
The JavaScript engine, a program that runs JavaScript code, contains both a call stack and a heap. For now, just know that the heap is a large, unstructured memory pool.
Why is the Call Stack Important?
JavaScript is single threaded, or synchronous. It can only do one thing at a time. We can give it 100 tasks to perform, but it can't perform all 100 tasks simultaneously. It has to go through the process of completing one task before moving onto the next. It's incredibly orderly.
Within the call stack, say for example, these 100 tasks are all functions. The call stack will stack each function's execution context on top of each other, in the order that they were called, like a pile of books, or boxes, or lego pieces, etc. At the top of the pile, is the current execution context we are within. Once that execution context is finished running, it'll be removed from the top of the pile. The book will be popped off, and it can move down the one directly below. And this will continue happening until the entire stack has been emptied, and the call stack returns to the global execution context, until something new is called.
But what happens when there is a task within a task, or a second function within another function when in that call stack? In that case, if a second function has been called within a function, a new execution context is created, and pushed onto the top of the stack. The execution of that first function is paused, the second function is run through, and once that is completed, it is popped off the the call stack, and we return to the execution context of the first function, which then continues until it's finished, and we return to the Global Execution Context.
While it might seem a little silly, here is an example of how switching execution contexts, and moving through the call stack works.
function first(){
console.log("Inside First.")
function second(){
console.log("First execution context paused, now inside Second.")
function third(){
console.log("Second execution context paused, now inside Third.")
}
third();
console.log("Return to second's execution context.");
}
second();
console.log("Return to first's execution context.");
}
first()
When first is called, it will print out to the console:
Inside First.
First execution context paused, now inside Second.
Second execution context paused, now inside Third.
Return into second's execution context.
Return to first's execution context.
Every time a new function was called, the call stack worked its way through the execution context until completed, before moving back to the previous function, until eventually, all execution contexts were finished, and we returned to the Global Execution Context.
The Global execution context will only pop off of the call stack when our program finishes, either by closing a browser window, or closing the terminal.
Further Reading:
Eloquent JavaScript
MDN Concurrency Model and the Event Loop
Top comments (2)
On error conditions, Javascript will stop executing the program. It is usually a good Idea to use try...catch on critical code sections. But is this a good practice to handle stack overflow?
This explains the try/catch much better than I can in regard to the call stack.
softwareengineering.stackexchange....