DEV Community

Michael Currin
Michael Currin

Posted on • Updated on

JavaScript's Event Loop

TL;DR

NodeJS uses an event loop (essentially a while loop) to run concurrent processes, for a smooth experience. This design is due to JavaScript and DOM operations being single-threaded. While others languages typically use multi-threading instead to achieve concurrency.

This single-threaded approach scales well in certain cases like for non-blocking UI or when thousands of threads incurs a cost of switching threads.

UPDATE: I originally thought the single-threaded approach was a limitation of Node and JS which prevents scaling, but it can be strength (see comment discussion), so I've updated this article.

The origin of NodeJS and the need for concurrency

I heard that NodeJS was created because JavaScript was the only language with an event loop.

JavaScript (or ECMAScript) was built for the browser /then repurposed to run server-side scripts applications under the NodeNS runtime environment. And Node that was built on event-driven programming to allow asynchronous tasks. This means concurrent processing can handle non-blocking tasks smoothly -- such as to fetch data while rendering UI and also checking for mouse-based events to fire.

Node achieves this through what is known as the event loop. The concurrency page on the Mozilla docs has an Event Loop section which says that it is usually implemented using a while loop which continously checks for events to fire.

The top of that page explains that this is not typical of concurrency other languages, like C or Java. These do not have the single-threaded limitation of JS and so use multi-threading instead of an event loop.

NodeJS and the event loop

In this talk by the Node creator, he explains in the first minute that the event loop (from the browser side) turned out to be necessary for the success of Node.

This is necessary because Node is single-threaded:

The event loop is what allows Node.js to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible.

And the reason Node is single-threaded is because JavaScript has to run in the browser as single-threaded -- since parallel operations on the DOM tree are not safe. See below.

Why then shouldn’t we just handle all the events we are subscribed to in old-fashioned parallel way? The reason is that we don’t want to change the DOM in parallel: this is because the DOM tree is not thread-safe and it would be a mess if we tried to do it. Because of this limitation, all our JavaScript code should be executed in single thread, while at the same time ensuring that it handles all the events and doesn’t lose any callback.

Follow the articles above for more detail on the event loop.

UPDATE: I found this series where the first article has some neat animations on the event loop - check it out.

More details on concurrency in other languages

Apache and Ruby using multiple threads but are inefficient at scale - see comment below.

Python has the threading library as well as multithreading library for multi-core processing.

Threading in Elixir is supposed to be a great strength for handling millions of requests efficiently.

New languages like Go and Rust can be very efficient at high-performance computing for modern computing tasks - in particular concurrent tasks that would be much slower in older languages.

Go was designed from the start to be fast to develop, fast and to handle concurrency with a "goroutine". See concurrency in the docs and an example of goroutines.

Oldest comments (7)

Collapse
 
koresar profile image
Vasyl Boroviak • Edited

Mate, this is plain wrong:

After some reading, I realized that things are the other way around - NodeJS was built, then the event loop was added to it because that was the only viable option for concurrency.

You need to research more. Here is Wikipedia for example:

en.m.wikipedia.org/wiki/Node.js

Dahl criticized the limited possibilities of the most popular web server in 2009, Apache HTTP Server, to handle a lot of concurrent connections (up to 10,000 and more) and the most common way of creating code (sequential programming), when code either blocked the entire process or implied multiple execution stacks in the case of simultaneous connections.

Ryan wanted non blocking I/O thus he selected the language which had the event loop - the JavaScript.

See his talk when he complains about Ruby, great language but awful blocking runtime.

Collapse
 
michaelcurrin profile image
Michael Currin

My apologies. I am drawing on what I find and my knowledge is limited in this area. I can't find the reference now but the source I found talked about alternatives being instigated for event loop and then event loop selected.

Fair enough that Apache and Ruby handle things poorly in this regard. I saw something about the cost of maintaining many threads increasing at scale.
Though Apache is mostly replaced by Nginx and Ruby is in decline from what I heard.

Still, languages like C and Java that are known for their speed use multi-threading to be non-blocking rather than an event loop, and Exilir's multi threading scales amazingly from talking to an Elixir dev. So Event Loop may handle things differently in a single thread but I don't see how Event Loop is a necessity (I don't know of other languages that use it, certainly not before Node existed).

Also NodeJS may indeed handle the event loop well from the articles I see on the topic. It's just unfortunate that because of the DOM background that basing a runtime on JavaScript required an event loop rather than a choice between multi-threading or single threaded event loop.

Collapse
 
koresar profile image
Vasyl Boroviak

I did years of multithreading (C, C#) before NodeJS (btw, NodeJS also has thread support).

The main problem with threads is switching between them. Each switch costs a lot of memory shifting and CPU cycles. Event loop is computationally cheap.

Hence, NodeJS is high performant in I/O heavy tasks (e.g. networking).

Thread Thread
 
michaelcurrin profile image
Michael Currin

Ah okay thanks for explaining.

Now I am curious why other languages don't do single threaded. or maybe it depends on the task and entire language setup. Or is it the difficulty of doing an event loop well that meant it took a long time for node to eventually be the first?

Thread Thread
 
koresar profile image
Vasyl Boroviak

Good questions. I wish I knew the answers.

Thanks for being open minded. You are a rare breed. 👍

Thread Thread
 
michaelcurrin profile image
Michael Currin

I've updated my post to be more balanced and to point to your initial comment

Thread Thread
 
koresar profile image
Vasyl Boroviak

Looks great! 👍👍👍