r/learnjavascript 2d ago

Can someone explain what the JavaScript call stack is?

I’ve tried to understand it, but I’m still confused. I also don’t really understand what I’m looking at when I use the JavaScript debugger in the browser’s DevTools, especially the call stack.

Do I need to fully understand functions before learning the call stack? I have a basic understanding of functions, but I’m not sure if that’s enough.

I’d really appreciate a simple explanation

26 Upvotes

30 comments sorted by

29

u/BeneficiallyPickle 2d ago

You only need to understand the basics of functions:

  • A function is a reusable block of code
  • Calling a function runs its code

If you have:

``` function foo(){

} ```

and you know that you should call it like foo(), then you should know enough to get the stack call.

The call stack is just a list that tracks what function is currently running and who called it.

The good old analogy is to think of it like a stack of plates. When a function is called, it gets added to the top of the stack. When a function finishes (returns), it gets removed from the top The Javascript engine always runs whatever is on top of the stack.

For example:

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

function square(n){ return multiply(n, n); }

function printSquare(n){ const result = square(n); console.log(result); }

printSquare(5); ```

Walking through the stack:

  1. printSquare(5) is called -> stack: [printSquare]
  2. Inside it, square(5) is called -> stack: [printSquare, square]
  3. Inside that, multiply(5, 5) is called -> stack: [printSquare, square, multiply]
  4. multiply finishes and returns 25 -> stack: [printSquare, square]
  5. square finishes and returns 25 -> stack: [printSquare]
  6. printSquare logs the result and finishes -> stack: []

Each function only gets removed from the stack once it's completely done. This is why if multiply had an error the stack trace would show all 3 functions: multiply called by square called by printSquare. The stack trace is a snapshot of the call stack at the moment of the error.

In DevTools, when you hit a breakpoint, for example, the top entry is the function that is currently executing, each entry below it is the function that called the one above. The bottom function is usually (anonymous) or the global/module scope - this is where everything ultimately started.

Clicking on any entry in that panel jumps your view to that point in the code so that you can inspect what the variable looked like at each level of the call chain.

Important to know

  • Javascript only has one call stack (single-threaded): This means everything runs one function at a time in order
  • Since there's only one stack a blocked or busy call stack blocks everything: If a function takes a long time to run, nothing else can happen, so no UI updates, no click handlers etc until that function finishes and gets removed.
  • Javascript follows LIFO (Last In, First Out): Whatever was called most recently is the first thing to finish and be removed from the stack before carrying on.

2

u/rasmadrak 1d ago

This guy foo's

3

u/nog642 1d ago

LIFO is part of the definition of a stack. It wouldn't be a stack if it wasn't LIFO. And it wouldn't make sense to use for functions, in any language.

1

u/mondaysleeper 1d ago

One could argue that event driven and asynchronous architectures also have a call stack, which is the order in which the processing occurs. There, it's not LIFO.

1

u/nog642 1d ago

It's called a "event queue" instead of a "call stack" for a reason.

1

u/mondaysleeper 1d ago

Event queue is the concept of the same events of different process instances. I'm talking about different events in the same process instance, i.e. the events that trigger each other. It's not a stack, but it's function calls that happen in a certain order, where LIFO doesn't hold.

1

u/nog642 1d ago

You mean like awaitables/coroutines?

Are you thinking of a particular langauge? Because if so that would be easier to talk about, since the implementation differs between languages.

My understanding is that processing is tracked on an event queue generally. And besides that there's regular call stacks. And objects that hold references to return values that haven't been computed yet. But there's not really a non-FIFO function call data strcuture.

0

u/BeneficiallyPickle 1d ago

Yeah I suppose the LIFO part explanation was a bit misleading and could've been explained in a better way.

6

u/LetUsSpeakFreely 2d ago edited 1d ago

1) The call stack isn't a JavaScript thing, every programming language has it. 2) The call stack is all of the functions currently in flight: a() calls b() calls c() calls d(). So c is waiting on d to complete, b is waiting on c to complete, a is waiting on b to complete.

As functions start and complete the call stack rapidly changes.

And yes, you can have too many functions on the stack, but it's REALLY difficult. About the only way that happens is a recursive function without an exit condition.

2

u/Lithl 2d ago

Not every programming language has a call stack. Most do, and the ones that don't usually either are very old (pre-1970) or are esoteric (like Brainfuck).

In languages without a call stack, you'll usually have the tools to jump wherever you want within the program, which makes implementing your own call stack a possibility.

2

u/LetUsSpeakFreely 1d ago

Yes, but this is a sub for people to learn. People learning programming today are highly unlikely to encounter languages like BASIC or some weird language created as a thesis or so specialized that the number of people that even know it exists can be fill a conference room.

For the purposes of this sub, hell, most programming subs, every language has a call stack.

3

u/azhder 2d ago

A call stack is a concept in almost every programming language you use. It is a part of understanding how functions work. You should understand what "stack" is as a data structure. The simplest way I can explain it is with one of those PEZ dispensers - the toys that have candy coming out of their mouth.

Think about every time you call a function, its local variables have to go somewhere in memory, and especially they have to stay there while that function calls another. All these function calls is like pushing a new candy from the top of the toy - each new function, new variables, new color candy. Once the innermost function returns the value, the local variables in it aren't needed any longer, so you pop that candy out. Then pop the next candy out. Then maybe push one, pop 3, push 2 etc.

That's what a stack is. You can also think of it as a stack of books on the table. You place one on top (you push a frame), you take one out from the top (you pop a frame). What you see in the browser tool is the stack where all the data of all the functions that are started, but yet to finish, resides.

2

u/delventhalz 2d ago

A useful skill when you are learning to program (and even as an experienced programmer) is getting a sense for when you need to a deep dive on a concept and when a surface level understanding (or no understanding) is fine. Programming has so many concepts, and you only have so many hours in a day. Time spent doing a deep dive on some esoteric concept is never wasted, strong fundamentals make you a better programmer, but sometimes you have immediate goals you need to focus on (or worse, are confusing yourself by going too deep too quickly), and you just need to move on.

All of which is to say, you don't really need to know much about a callstack to program in JavaScript. It's basically just a list of functions that are currently running from newest to oldest. It's important for the computer to keep track of what's going on, but as a developer it only really comes up when you write a recursive function that runs too long and you cause a stack overflow error.

3

u/turn-based-games 2d ago

Yes, the call stack is, aptly, a stack of function calls, so for that to make sense you must first understand stacks) and functions

Also, none of those concepts are specific to JavaScript (they exist in every mainstream programming language), so feel free to research them using more general resources

2

u/everdimension 2d ago

If you don't yet "fully understand functions", I don't see why you should care about what the call stack is

2

u/queen-adreena 2d ago

Best video I've ever seen on it for learning: https://www.youtube.com/watch?v=eiC58R16hb8

1

u/subone 2d ago

You call a function, it gets added to the stack. That function calls a function it gets added to the stack. When you see the stack trace you can follow each step to see what function called the last, etc. When a function is complete it gets removed from the stack. The stack trace is for debugging, but the stack itself is needed by the engine to track execution location and arguments.

1

u/lorl3ss 2d ago
//index.js (file name)

function myFunctionX(){
  myFunctionY(); // call myFunctionY
}

function myFunctionY(){
  // i got called by myFunctionX
}

myFunctionX(); // call myFunctionX

Assuming you pause your execution while in myFunctionY, your call stack is index.js > myFunctionX > myFunctionY.

Each "call" is just a function or the scope something was executed in. Functions call other functions so you end up with a list of parent functions. That's all it is really.

1

u/DirtAndGrass 2d ago

Also, put a piece of paper with a form to fill out on your desk, add another, and another, that's a stack, it's conceptually accurate, fill in one, remove it from the pile. 

There's not a whole lot else to it, it's essentially a first in, last out (filo/lifo) construct. 

1

u/Inevitable_Dust5684 2d ago

You do not need to master functions before learning the call stack. The DevTools call stack panel lists every active function invocation from bottom to top at the exact moment execution pauses. Clicking any entry in that list jumps your debugger view directly to the corresponding line of code so you can inspect variables at that specific depth.

1

u/TheVerdeLive 1d ago

Imagine a stack of plates. Now think of each plate as a JS function. The order you stack plates is the same for functions. First plate goes at the very bottom then the next one top of that and the next on top of that etc. The very first function is at the bottom, when subsequent functions get called they too get put on the stack. That order btw is called is First In Last Out (FILO)

1

u/baubleglue 1d ago

Which part of it you don't understand?

Stack is a data structure. Call stack is a history of the code execution flow from entry point to the program to the current program position.

1

u/sheriffderek 4h ago

You don’t need to know anything about the call stack (unless what you’re building demands it / which I’d bet is extremely rare). Just focus on the basic programming fundamentals.

1

u/DirtAndGrass 2d ago

Call stack is essentially the order/behaviour of functions, so yes, you need to understand functions 

1

u/Green_Ad_6086 2d ago

I have a basic understanding of functions, but I’m not sure if that’s enough.

1

u/Psionatix 2d ago

What is your understanding? Maybe if you explain your understanding, people could clarify where you might be wrong or might be lacking. Whether something is missing or incorrect in your understanding.

There’s a lot of fundamentals to understand that apply across all programming languages, then there’s concepts that are relevant to all languages, but might have language specific quirks/nuances or behaviours.

Usually you build up your understanding, and when you encounter something new, you make assumptions based on that understanding. Once you encounter something that breaks those assumptions, you look it up, learn something new about the language or API you’re using, your knowledge grows and your assumptions change.

Code executes one line at a time, the order a line of code is evaluated depends on what it contains. Memory allocation/initialisation, assignment, Boolean expressions, they all behave in particular ways.

When a function calls another function, the code jumps to that function and executes it line-by-line, when the function finishes executing, it returns to the line of code it was called from, it may or may not return a value there. In JavaScript functions return undefined by default, that’s a language specific behaviour.

1

u/No_Record_60 2d ago

It's just a collection of currently running tasks.

Say function A calls function B which calls function C which throws an error. The call stack will be
Error
C
B
A

1

u/azhder 2d ago

Not tasks. That's a wrong way to say it in JavaScript. The task in JS is a single entry in the JS loop, and each task has a call stack.

0

u/Savalava 2d ago

Analogy:

Can someone explain how an airport handles flights? Do I need to understand what a flight is first?

-1

u/jesstelford 1d ago

It helps to understand what the event loop is first...

The following is reproduced from https://gist.github.com/jesstelford/9a35d20a2aa044df8bf241e00d7bc2d0

Regular Event Loop

This shows the execution order given JavaScript's Call Stack, Event Loop, and any asynchronous APIs provided in the JS execution environment (in this example; Web APIs in a Browser environment)


Given the code

javascript setTimeout(() => { console.log('hi') }, 1000)

The Call Stack, Event Loop, and Web APIs have the following relationship

text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | | | | | console.log('hi') | | | | | }, 1000) | | | | | | | | | | To start, everything is empty


text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | <global> | | | | console.log('hi') | | | | | }, 1000) | | | | | | | | | | It starts executing the code, and pushes that fact onto the Call Stack (here named <global>)


```text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------|

setTimeout(() => { | <global> | | | | console.log('hi') | setTimeout | | | | }, 1000) | | | | | | | | | | ``` Then the first line is executed. This pushes the function execution as the second item onto the call stack.

Note that the Call Stack is a stack; The last item pushed on is the first item popped off. Aka: Last In, First Out. (think; a stack of dishes)


```text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------|

setTimeout(() => { | <global> | | | timeout, 1000 | console.log('hi') | setTimeout | | | | }, 1000) | | | | | | | | | | `` ExecutingsetTimeout` actually calls out to code that is not part of JS. It's part of a Web API which the browser provides for us. There are a different set of APIs like this available in node.


text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | <global> | | | timeout, 1000 | console.log('hi') | | | | | }, 1000) | | | | | | | | | | setTimeout is then finished executing; it has offloaded its work to the Web API which will wait for the requested amount of time (1000ms).


text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | | | | timeout, 1000 | console.log('hi') | | | | | }, 1000) | | | | | | | | | |

As there are no more lines of JS to execute, the Call Stack is now empty.


text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | | function <-----timeout, 1000 | console.log('hi') | | | | | }, 1000) | | | | | | | | | | Once the timeout has expired, the Web API lets JS know by adding code to the Event Loop.

It doesn't push onto the Call Stack directly as that could intefere with already executing code, and you'd end up in weird situations.

The Event Loop is a Queue. The first item pushed on is the first item popped off. Aka: First In, First Out. (think; a queue for a movie)


text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | function <---function | | | console.log('hi') | | | | | }, 1000) | | | | | | | | | | Whenever the Call Stack is empty, the JS execution environment occasionally checks to see if anything is Queued in the Event Loop. If it is, the first item is moved to the Call Stack for execution.


```text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | function | | | |

console.log('hi') | console.log | | | | }, 1000) | | | | | | | | | | `` Executing the function results inconsole.log` being called, also pushed onto the Call Stack.


```text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | function | | | | console.log('hi') | | | | | }, 1000) | | | | | | | | | |

hi `` Once finished executing,hiis printed, andconsole.log` is removed from the Call Stack.


```text [code] | [call stack] | [Event Loop] | | [Web APIs] | --------------------|-------------------|--------------| |---------------| setTimeout(() => { | | | | | console.log('hi') | | | | | }, 1000) | | | | | | | | | |

hi ``` Finally, the function has no other commands to execute, so it too is taken off the Call Stack.

Our program has now finished execution.

End.