You have probably heard of terms like “V8,” “event loop,” “call stack,” and “callback queue.” In this post, we are going to examine what these terms mean, how they relate to one another, and, more generally, how JavaScript works. Javascript is a powerful language that has stood the test of time and continues to gain popularity. By cultivating a strong understanding of its core concepts, you'll be able to write better code and better apps.

Let's start by defining V8. V8 is a popular open source JS Engine. It is the engine inside Chrome that runs the JavaScript code. But when running a JavaScript in the browser, there's more involved than just the JS Engine. Most JavaScript code makes use of web APIs like DOM, AJAX, and Timeout (setTimeout). It turns out, however, that none of these APIs are provided by the engine; instead, they're provided by the browser.

In the picture below we can see an overview of the elements involved in the JS execution in the browser. The V8 Engine contains a call stack. The engine communicates with the web APIs, and there is also a queue and a mysterious event loop. In the following sections, we are going to describe in more details this theoretical overview (If you are running JS on the back-end, the idea is pretty much the same, but instead of web APIs, you have NodeJS APIs).

 
Untitled drawing

Javascript is a single threaded programming language, which means it has a single call stack and can do one thing at a time.

The call stack is a mechanism so the interpreter knows its place in a script. When a script calls a function, the interpreter adds it on the top of the call stack. When the current function is finished, the interpreter takes it off the stack (Last In, First Out).

Consider this simple JS function:

Let’s see the call stack in action when this code is executed.

1. The interpreter starts calling foobar.

null

2. foobar is added to the stack.

null

3. The interpreter steps into the function, and console.log(‘A’) is called and added to the top of the call stack.

null

4. console.log(‘A’) is executed, and the letter “A” is printed in the console.

null

5. console.log(‘A’) is removed from the call stack since its execution has been completed, and the interpreter moves on to the next command.

null

6. console.log(‘B’) is processed the same way as the previous one, and the letter 'B' is printed in the console.

null

7. console.log(‘B’) is removed from the stack, and the interpreter moves on.

null

8. console.log(‘C’) is processed the same way as the previous ones, and the letter 'C' is printed in the console.

null

9. console.log(‘C’) is removed from the stack, and the end of the foobar function is reached.

null

10. foobar is also removed from the call stack, which becomes empty again.

null

Cool! But what if we have a very slow operation, such as image processing or network requests? Since JS can do only one thing at a time, this slow operation will block all other operations until it is finished. During this time, the user won’t be able to interact with the page; the browser will simply freeze. This is not ideal, and this is not what actually happens.

JavaScript concurrency model is different from other languages like C and Java, and it is based on an “event loop.” In this model, we run an operation and give it a callback function that is going to be executed later when the first operation is completed. This way, the call stack is not blocked and other operations can be added to it. Let’s modify our previous example a little bit so we can see how these async callbacks are handled by the browser:

1. Now, instead of calling console.log(‘B’) directly, we are putting it inside a callback function that will be called later. The setTimeout is an asynchronous function that we are using to simulate a slow operation. Here again, the interpreter starts by calling foobar.

null

2. The first steps are the same: foobar is added to the call stack, the interpreter steps in, adds console.log(‘A’) to the stack, prints the letter 'A,' and removes the call from the stack. Then the interpreter reaches the setTimeout function and adds it to the call stack.

null

3. As we noted in the beginning of this article, setTimeout is provided for us by the Web API. So it receives the setTimeout call alongside the callback and starts processing it. 

null

4. Now the call to setTimeout itself is completed, so it can be removed from the stack. The Web API continues the processing, but the call stack is not blocked anymore, so the interpreter can move to the next command. 

null

5. This next step is executed normally, and the letter 'C' is printed to the console.

null

6. console.log(‘C’) is removed from the call stack, and so is foobar since the interpreter has reached the end of the function. The call stack is empty again.

null

7. Ok… we are almost there, but what about the letter “B”? How is the callback sent to the call stack so it can be executed? When an asynchronous call is completed, the callback function is pushed to the Task Queue. 

null

8. This is where the last piece of the puzzle comes in--the event loop. The event loop has one simple job: it looks at the call stack and the task queue, and if the stack is empty, it takes the first item in the queue and sends it back to the call stack. 

null

9. Finally, the callback is executed, the letter "B" is printed in the console, and the callback is removed from the call stack.

null

And that’s it! If you want to dive a little deeper into the concepts presented above, be sure to check the links below.

Happy coding!

• Concurrency model and Event Loop: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

• How JavaScript works: an overview of the engine, the runtime, and the call stack: https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf

• Chrome V8: https://en.wikipedia.org/wiki/Chrome_V8

Author

Rafael Bicalho

Rafael Bicalho is a UI Engineer at Avenue Code. He is a fan of technology, coffee and programming.


How to Improve the Relationship Between UX and Development Teams in an Agile Context - Part 1

READ MORE

Directives to the Point: Manipulating the DOM with Angular

READ MORE

Creating Adaptive/Responsive HTML Emails with MJML

READ MORE