Understanding Javascript Function Executions — Call Stack, Event Loop , Tasks & more — Part 1

Web developers or Front end engineers, as that’s what we like to be called, nowadays do everything right from acting as a source of interactivity inside the browser to making computer games, desktop widgets, cross-platform mobile apps or writing it on server side (most popularly with node.js) to connect it with any database — achieving near-ubiquity as a scripting language. It is therefore important to get to know about the internals of Javascript, to use it better and effectively and this is what the article is about.

The Javascript ecosystem has become more complicated than ever and will continue to become more. The tooling that is required to build a modern web app is overwhelming with Webpack, Babel, ESLint, Mocha, Karma, Grunt…etc, etc — what should I use and which tool is doing what? I found this web comic, which perfectly illustrates the struggle of today’s web developers.

Javascript Fatigue — What it feels like to learn Javascript

All this apart, what every Javascript developer first needs to do before diving deep into using any framework or library out there in the fish market is to know the basic foundation of how all of this is done internally at the root level. Mostly all JS dev might have heard the term V8, chrome’s Runtime but some might even didn’t really know what that meant, what that did. I initially for the first year of my professional career as a developer, didn’t know much about all these fancy terms either as it was more about getting the work complete first. That didn’t satiate my curiosity about how the hell Javascript is able to do all this stuff. I decided to dig deep, rummaging around google and came across few good blog posts including this Philip Roberts, a great talk at JSConf on the event loop and so I decided to summarize my learning and share it. As there are plenty of things to know about, I have divided the article into 2 parts. This part will introduce the terms that are commonly used and in the second part the linking between all those.

Javascript is a single threaded single concurrent language, meaning it can handle one task at a time or a piece of code at a time. It has a single call stack which along with other parts like heap, queue constitutes the Javascript Concurrency Model (implemented inside of V8). Let us first go through each of these terminologies :

Visual Representation of JS Model(credits)

1.Call Stack :- It’s a data structure which records the function calls, basically where in the program we are. If we call a function to execute , we push something on to the stack, and when we return from a function, we pop off the top of the stack.

JS Stack Visualization (GIF)

As we run the above file, we first look for the main function where all the execution will start. In the above, it starts from console.log(bar(6)), which is pushed on to the stack, next frame on top of it is the function bar with it’s arguments which in turn calls function foo which is again pushed on to the top of stack and it returns immediately and so is popped out of stack, similarly bar is then popped out and finally console statement is popped out printing the output. All this happens in jiffy (in ms) one at a time.

You all must have seen the long red error stack trace sometimes in our browser console, that basically indicates the current state of the call stack and where in the function it failed in a top to bottom manner just like stack (see image below)

Error stack trace(credits)

Sometimes, we get into an infinite loop as we call a function multiple times recursively and as for Chrome browser, there is a limit on the size of the stack which is 16,000 frames , more than that it will just kill things for you and throw Max Stack Error Reached (image below).

(credits)

2.Heap :- Objects are allocated in a heap i.e mostly unstructured region of memory. All the memory allocation to variables and objects happens here.

3.Queue :- A JavaScript runtime contains a message queue, which is a list of messages to be processed and the associated callback functions to execute. When the stack has enough capacity, a message is taken out of the queue and processed which consists of calling the associated function (and thus creating an initial stack frame). The message processing ends when the stack becomes empty again. In basic words , these messages are queued in response to external async events(such as a mouse being clicked or receiving the response to an HTTP request), given a callback function has been provided. If, for example a user were to click a button and no callback function was provided — no message would have been enqueued.

Event Loop

Basically, when we evaluate the performance of our JS code, so a function in a stack makes it slow or fast, console.log() will be fast but performing iteration with for or while over thousands or millions of line items will be slower, and will keep the stack occupied or blocked. This is termed as blocking script, which you have read or heard about in Webpage Speed Insights.

Network requests can be slow, the image requests can be slow, but thankfully the server requests can be done through AJAX, an asynchronous function. If suppose, these network requests are made through synchronous functions, then what would happen? The network requests are send to some server, which is basically another computer/machine somewhere. Now, computers can be slow sending back the response. In the meantime , if I click some CTA button, or some other rendering needs to be done, nothing will happen as the stack is blocked. In multi threaded language like Ruby, it can be handled, but in single threaded language like Javascript, this is not possible unless function inside the stack returns a value. The webpage will hell breaks loose as the browser can’t do anything. This is not ideal if we want fluid UI for the end user. How do we handle this?

“Concurrency in JS— One Thing at a Time, except not Really, Async Callbacks”

The easiest solution is by using asynchronous callbacks, which means that we run some part of code and give it a callback (function) which will execute later. We all must have encounter asynchronous callbacks like any AJAX request using $.get(),setTimeout(),setInterval(), Promises, etc. Node is all about asynchronous function execution. All these async callbacks doesn’t run immediately and are going to run some time later, so can’t be pushed immediately inside the stack unlike synchronous functions like console.log(), mathematical operations. Where the hell then they go and how they are handled?

If we see a network request in action in Javascript like in above code:

  1. The request function is executed, passing an anonymous function in onreadystatechange event as a callback to execute when a response is available sometime in the future.
  2. “Script call done!” is immediately output to the console
  3. Sometime in the future, the response comes back and our callback is executed, outputting its body to the console.

The decoupling of the caller from the response allows for the JavaScript runtime to do other things while waiting for your asynchronous operation to complete and their callbacks to fire. 2This is where browser APIs kicks in and call its APIs, which are basically threads created by browser implemented in C++ to handle async events like DOM events, http request, setTimeout, etc.(After knowing this, in Angular 2, Zones are used which monkey patches these APIs to cause runtime change detection, which I can get a picture now, how they were able to achieve it.)

Browser Web APIs- threads created by browser implemented in C++ to handle async events like DOM events, http request, setTimeout, etc.

Now these WebAPIs can’t themselves put the execution code on to the stack, if it did, then it would randomly appear in the middle of your code. The message callback queue discussed above shows the way. 3Any of the WebAPI pushes the callback onto this queue when it’s done executing. The Event Loop now is responsible for the execution of these callbacks in the queue and pushing it in the stack, when it is empty 4. Event loop basic job is to look both at the stack and the task queue, pushing the first thing on the queue to the stack when it see stack as empty. Each message or callback is processed completely before any other message is processed.

while (queue.waitForMessage()) {
queue.processNextMessage();
}
Javascript Event Loop Visual Representation

In web browsers, messages are added any time an event occurs and there is an event listener attached to it. If there is no listener, the event is lost. So a click on an element with a click event handler will add a message — likewise with any other event. The calling of this callback function serves as the initial frame in the call stack, and due to JavaScript being single-threaded, further message polling and processing is halted pending the return of all calls on the stack. Subsequent (synchronous) function calls add new call frames to the stack .

In the next part, I will show a visual animation of code execution for the above procedure, further explaining what are different types of async functions like tasks, micro-tasks and whose priority in the queue comes first. Also, the hacks like zero delay used to perform some functions.

Hope, you like it, feel free to post your valuable comments, to help me improve.