Evgeniy, senior developer of Noveo, prepares the principles of the Event Loop
The Event Loop is one of the most important aspects in JavaScript, knowledge of which allows you to write more efficient code. In this article, we will look at how the main thread works in JavaScript and how it handles asynchronous functions.
Illustration for the article “How to Write Effective JavaScript Code Using the Event Loop”
For a long time, I’ve been writing JavaScript code without fully understanding how it works under the hood. Basically, in order to code in JavaScript, you don’t need to know how it works from the inside, but it will make your code better and allow you to look at some things in the language from a different angle.
All JavaScript code is executed in a single thread, which means that only one thing can be processed at a time. On the one hand, this is a useful limitation, since it allows us not to think about the specifics of working with parallelism. On the other hand, we must constantly monitor the code and make sure that synchronous operations (infinite loops, requesting data over the network) do not block our thread.
In most browsers, each tab has its own event loop, this allows you to isolate the tabs from each other, and if one hangs, the others will continue to work. Otherwise, one hung operation could break the entire browser across all tabs.
In fact, the environment can simultaneously manage a large number of “event loops” to process API requests. WebWorkers also have their own event loop.
A JavaScript developer must be aware that his code is always executed in the same event loop and be careful not to block it.
Blocking Event Loop
Any code that takes a long time to execute before returning control to the main thread will block the execution of any JavaScript code on the page. This also blocks the user interface, and the user cannot interact with it (click, scroll the page, etc.).
Almost all I / O operations in JavaScript are non-blocking – network requests, file system operations in Node.js, etc. The exception is blocking operations, which is why callbacks are so popular in JavaScript, and more recently all they are starting to use Promise and async / await more often.
Call stack
The call stack is a LIFO (Last In, First Out) queue.
The event loop continuously loops through the call stack looking for a function to be processed. When doing so, it adds any function call it finds to the call stack and executes each one in order.
If you are familiar with the call stack in the debugger or browser console, then the example below will be clear to you. The browser looks up the function names on the call stack to tell you which function is initiating the current call:
Examples of working with Event Loop
The function names bar, baz, foo are taken as examples.
Basically as expected.
Let’s take a closer look at how this code is processed through the Event Loop. When the code is executed, foo () is called first, inside foo (), bar () is called first, and then baz ().
At this point, the call stack looks like this:
The event loop at each iteration checks if there are any calls on the stack, and if so, executes them:
This process continues until the stack is empty.
Function order
There is nothing specific in the example above: JavaScript parses the code and determines the order in which the functions are called.
Let’s see how we can change the order in which functions are called, making sure that a particular function is called last. To do this, we will make a call to our function through the browser API:
setTimeout (() => {}, 0);
Consider the following example:
Illustration for the article “How to Write Effective JavaScript Code Using the Event Loop”
The result of executing this code may be unexpected for some:
Illustration for the article “How to Write Effective JavaScript Code Using the Event Loop”
When this code is executed, foo () is called first. Inside foo (), we first call setTimeout, passing bar as an argument, and set the time interval to 0 so that the call happens as quickly as possible. Then we call baz ().