My Blog



Javascript – Under The Hood

Most of the people that are into software development nowadays have written plenty of lines of Javascript code. But how many developers do really know what is happening in the browser when a small piece of JS code is being executed? Either you want to use a JS framework, either plain JS (Vanilla), understanding the way Javascript is actually working can bring your development skills to the next level. So let’s take a look, under the hood.

What is Javascript?

JavaScript, often abbreviated as JS, is a single-threaded, non-blocking, asynchronous, concurrent programming language. It has a heap and a call stack, an event loop, a callback queue and some other APIs for working with text, arrays, dates, regular expressions, and basic manipulation of the DOM.

Ok, that’s a complicated definition, so let’s dive deeper. A Javascript Runtime (V8 for example) consists of the heap, where memory allocation happens and the call stack, where you can find the execution context. Javascript is a single-threaded language which means that it can do one thing at a time. This also means that Javascript has a unique call stack, which basically records where in the program we are, if we step into a function, we put something on to the stack, if we return from a function, we pop off the top of the stack. That’s all the stack can do.

Is it asynchronous or synchronous?

Javascript is also non-blocking and asynchronous. Let’s say we have a JS script that calls 3 times a function that does a synchronous HTTP request. The first call would have been put into the stack, we would have to wait until our backend gives us a response and then proceed with the next function call. And if the backend for some reason needed 2 hours to respond, Javascript would wait for 2 hours before proceeding. Why is this a problem? Because we execute our JS code in browsers. And if the JS call stack has pending things on it, the browser can’t do anything else, it can’t render, it can’t run any other code, it’s stuck. Not ideal if we want to have a fluid User Experience, so we simply can’t block the stack.

So how do we deal with this? Asynchronous callbacks. These are non-blocking functions in the browser (equally in node) and they are all made asynchronous, which basically means we run some code, give it a callback and run that later. If you have worked with JS, you have also seen asynchronous functions. The most common example is setTimeout. So if we put some code as a setTimeout callback, what the browser does is queueing this piece of code for the future and then skips on to the code that comes next.

This behaviour doesn’t sound like a common task for the call stack right? It doesn’t even sound like single-threaded execution, but more like concurrency. The reason why we can execute things concurrently is that the browser is much more than just the Javascript Runtime. The JS Runtime itself can do only one thing at a time, but the browser gives us the ability to execute code concurrently by offering us the WebAPIs, the Callback queue and the Event loop.

Let’s see them in action, step by step, by analysing a small piece of JS code.

const asynchronousExample = function() {
    console.log(‘hi’); 	// console.log A

    setTimeout( () => {
        console.log(‘asynchronous’); // console.log B
    }, 500);

    console.log(‘javascript’); // console.log C

Here is what happens in the browser when we invoke the asynchronousExample function:

1) The console.log “A” is being pushed into the stack
2) ‘hi’ is being logged
3) setTimeout is pushed into the stack
4) Its callback is being forwarded into the WebAPI and the API’s timer starts counting for 500 ms.
5) The console.log “C” is being pushed into the stack.
6) ‘javascript’ is being logged.
7) When the timer reaches 0, it forwards the callback to the task/callback queue.
8) The event loop checks if the stack is empty and executes the console.log “B”
9) ‘hi javascript asynchronous’ is written in the console.

That’s what the event loop is doing. It makes sure that the method calls that lie into the stack do not conflict with the ones that come from the task/callback queue. The callback queue is just receiving the callbacks from the browser’s Web APIs.

In the following video the execution process is being visualised:

The interesting part is that several commands like this (commands related to DOM manipulation and HTTP requests) don’t exist in the Javascript Runtime either. You can find them in those Web APIs that lie within the browser (or Node) and the Javascript Runtime has access to them. Therefore, the definition of Javascript that lies on the beginning of this article is partially correct. Javascript is concurrent and asynchronous, because it’s being executed within environments (browser, node) that extend its possibilities. The JS Runtime itself is single-threaded and synchronous.

You can watch a visualisation of this process in this beautiful tool made by Philip Roberts:

Experiment with your own functions and see them in action.

I hope that after reading this article you have a better understanding of the mechanics behind Javascript. Being able to explain how a language is working will make you much more confident during interviews, but will also help you with your every day work. In another article we will dive deeper into prototypal inheritance, coercion, dynamic typing and other weird things that our beloved Javascript is doing.

Have a great and productive week!

Leave A Comment