The Event Loop Explained

March 10, 2020

The event loop is not just for JavaScript. It is the standard that defines how a web browser front end works. Understanding the event loop is the first step to creating great web-based software.

Parallel Processing

In the early 2000s, CPU manufacturers hit a wall. At the time, clock cycles were king. The more cycles your CPU could produce, the more instructions it could perform per second, and the faster the machine. With increased cycles came increased heat - too much to dissipate.

Clever manufacturers instead opted to increase the number of cores, allowing for performance-seeking processes to access an entire core, leaving the rest for other tasks. Clever programmers used specialized languages to access these other cores and tease out speed. Nowadays, those same clever developers use these multiple cores for synchronous tasks, such as background processes or running two applications at once.

JavaScript (JS) is not that clever. JS is a single-threaded language, meaning that it can access only one core to execute a single line of instructions. This is a big limitation. For example, if there was a timer on a website and another JS event were to happen, such as an animation, the timer would halt while the browser handled the other instructions. This limitation is detrimental for the future of JavaScript development. The solution? The event loop.

Event Loop

The event loop is not just for JavaScript. It is the standard that defines how a web browser front end works.

event loop 1

The purple ball represents the current state of the event loop. Like a movie, the browser redraws the screen on every frame. Between frames, JavaScript runs. When the script event ends, control is passed back to the browser to redraw any changes that occurred. This keeps animations or UX elements fluid while still computing the JavaScript in the background.

Clogging the Drain

In a new tab, try pasting the following code into your browser’s console. You will have to end the tab’s process afterwards.

while(true){ console.log("Section is cool") }

Try selecting text or clicking on buttons. Can’t? Let’s see why.

Here is the event loop while our code is running.

blocked event loop

It is stuck in our JavaScript infinite loop. The website can’t re-render or handle other events, like clicks, because we haven’t given control back to the browser.

This is called blocking the event loop. Long tasks like loops can unintentionally block the event loop, and make web apps and sites feel slow and unresponsive.

Unclogging the Drain

Fortunately, we have tools to get around this. Copy this code into a browser console.

let loop = setInterval(() => {
	console.log("Section is cool")
}, 0)

In this case, we use setInterval(foo, 0). This adds a callback to the callback queue. Functions like setInterval, setTimeout, and promises put code in the queue. When all tasks end, JavaScript will start running code in the queue in a first in, first out structure. We can use these asynchronous tools to write non-blocking code.

Welcome to Hell

Asynchronous JavaScript is not perfect. Some JavaScript developers describe callback hell when code contains many functions, usually nested, that add callbacks to the callback queue. This means some functions are not resolved top to bottom, and instead are called at a later time. Take the following code for example:

function callbackFunction(){
	console.log("called foo")
}
foo(callbackFunction) //calls callbackFunction as async
console.log("finished script")

While seemingly innocuous, this code has some interesting aspects to it. Due to hoisting (a subject for another article), the function callbackFunction is defined. Then we invoke foo. This places callbackFunction on the callback stack; “finished script” is now logged. Now that the stack is clear, callbackFunction can be invoked and print “called foo” to the log. We end up with a console log that looks like

finished script
called foo

This non-linear execution is difficult to understand, and leads to callback hell and undefined behavior.

Importance

As browsers and JavaScript engines become faster and more powerful, client-side JavaScript is more efficient. Non-blocking asynchronous code is crucial for responsive web apps that use web/server requests or complex processes during run-time.

Understanding the event loop is the first step to creating great web-based software.


About the author

Nadiv Gold Edelstein

Nadiv Gold Edelstein is a sophomore at University of Colorado at Boulder. He enjoys full stack development, teaching computer science, and being strongly opinionated about code.

This article was contributed by a student member of Section's Engineering Education Program. Please report any errors or innaccuracies to enged@section.io.