JavaScript Call Stack Explained

An Introduction to JavaScript’s Call Stack, Event Loop and Event Queue

Ellen Park
Level Up Coding

--

Photo by Kelly Bork on Unsplash

What is the Call Stack?

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. — MDN Web Docs

The call stack keeps track of functions to be executed. When we call a function, it’s added, or pushed to the top of the call stack. When the function returns, it’s removed, or popped from the call stack. Any asynchronous functions (fetch, setTimeout, async, etc.) are moved to the event queue (more on that later).

Most likely, you’ve seen the call stack in your console when an error is thrown.

From the above image, we can see the current state of the call stack (a, b, c) and when the error occurred.

How does the Call Stack Work?

You might have heard that JavaScript is single-threaded. This means it has only one call stack and it can only process one statement at a time. The call stack follows the LIFO (Last In, First Out) principle, which means it will always process the call on top of the stack first.

When a function is called it’s added to the stack. When a function calls another function, it’s added on top of the calling function.

Given the above block of code, we can assert that:

  1. First, sayHi is invoked and added to the call stack (sayHi has not yet resolved).
  2. sayHi then invokes sayBye and adds sayBye to the call stack (both functions are still unresolved).
  3. At this point, the call stack status is currently:

4. sayBye is now at the top of the call stack. It will execute and print out ‘Bye’ to the console. Then, it is removed from the top of the call stack.

5. Now, sayHi is at the top of the call stack. It will print out ‘Hi’ to the console then be removed from the call stack. The call stack is now empty.

6. The final output:

How does the Event Loop work?

When an async function is called it does not go to the call stack. Instead, it’s forwarded to the event queue. The connection between the call stack and event queue is facilitated by the event loop. The event loop is constantly checking the call stack. If the call stack is empty it adds the first function in the event queue to the call stack for execution. Otherwise, it continues processing code in the call stack.

What is the Event Queue?

The event queue is where async code waits for execution. Unlike the call stack the event queue follows the FIFO (First In, First Out) principle, which means it will always process calls in the same order they were added to the queue.

It’s important to note that the event queue will only begin executing when the call stack is empty. If the call stack is already processing code, the event loop will not add any functions from the event queue. The event loop will not resume until the call stack has cleared.

Take a look at the following code.

As expected, the above code will immediately print out ‘foo’ in the console. Then, 1 second later it will print out ‘bar’.

How about the below code?

Here, setTimeout is set to 0. Because of this, you might think bar() will execute immediately resulting in ‘bar’ being printed before ‘foo’. But this is not the case. Both code snippets will result in:

Although setTimeout is set to 0, it is still forwarded to the event queue. This means it cannot execute until the call stack has completely cleared.

Additional Resources

--

--

Full Stack Software Engineer specializing in Javascript, React and Ruby on Rails