Understanding Node.js

Warning: Illegal string offset 'filter' in /var/sites/t/theproactiveprogrammer.com/public_html/wp-includes/taxonomy.php on line 1409

I have never worked with Node.js, and prior to this week had never gotten around to exploring it at all. I have however been aware for a long time that it is something that I should know more about. Therefore, as a first step, I decided to look into what exactly Node.js is and what I need to know about it. As always my first port of call was the official definition. So, from nodejs.org we have:

Node.js® is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

There’s a lot of information in those two sentences, in fact, enough to write a whole blog post on.

Clearly I am very far from a Node.js expert, what I am doing here is trying to learn a little about Node.js and sharing what I have learnt. If anyone who is more experienced with Node.js can point out anything I have got not quite right then please do let me know in the comments!

So let’s take those two sentences apart, and look at what is being said.

“Node.js is a platform built on Chrome’s JavaScript runtime…”

A light bulb moment for me was reading the following from An Absolute Beginner’s Guide to Node.Js (which I found to be a great introduction).

Node.js is just another way to execute code on your computer. It is simply a JavaScript runtime.

It really is that simple. JavaScript works on websites because browsers can interpret it. Although in most cases JavaScript will produce the same results in different browsers, there are differences in the way that browsers interpret certain statements, and Node.js is built on the Chrome JavaScript runtime, for reasons listed on Wikipedia.

In browsers we run JavaScript by including it in html files. With Node.js, we use the node command from the command line, passing the name of a JavaScript file as a parameter.

“…for easily building fast, scalable network applications.”

Although Node.js is indeed just a JavaScript runtime, when people talk about its benefits and compare it with other technologies, they tend to be referring to Node.js being used as a web server, which is its most common use.

So how can a JavaScript runtime be used as a web server?

The answer comes from the fact that there are many modules (JavaScript libraries) available for use in Node.js, one of which is named http and exposes a function,  http.createServer([requestListener]), which returns a new web server object. This object exposes a function, server.listen(port[, hostname][, backlog][, callback]), which instructs the server to begin accepting connections and server.on([eventname], [callback]) which instructs the server what to do with specific types of events, such as request and error.

Here’s a very simple example:

It is however more convenient to achieve the same result by including the optional requestListener parameter to createServer:

So how are node web applications fast and scalable?

To answer this question we now need to talk about how Node.js web servers work in a fundamentally different way to traditional web servers (for traditional web servers, think Apache or IIS).

What makes Node.js fast and scalable is its event-driven, non-blocking I/O model, which brings us to the next part of our official definition.

“Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient”

It is the event-driven nature of Node.js that sets it apart from traditional web server technologies. By event-driven, what we mean is that Node.js uses callback functions to implement asynchronous programming. This approach will be familiar to JavaScript programmers, and is discussed in my article on JavaScript Promises. The ‘event’ is simply the trigger for the callback function to execute.

In a single-threaded language such as JavaScript, it is often crucial that time-consuming operations (I/O) are non-blocking, that is, that they can be performed asynchronously. Otherwise, everything would have to stop and wait for those operations to complete. In client-side programming, this would mean that the browser would ‘freeze’. Web servers on the other hand need to be able to perform asynchronous operations in order to handle multiple concurrent requests.

Apache and IIS implement a multi-threaded architecture to handle concurrent requests (e.g. thread-per-connection or thread-per-request). This can be problematic for two main reasons:

  1. Multi-threaded programming is hard.
  2. Spawning and managing multiple threads is memory-expensive.

So in other words, the event-driven, non-blocking I/O model implemented by Node.js is ‘lightweight’ and ‘efficient’ (and probably easier to code than multi-threading). Behind the scenes the Node.js ecosystem does use multiple threads, but this detail is hidden from the developer.

If you are struggling to understand my attempt at explaining this stuff, I would urge you to read Node.js, Doctor’s Offices and Fast Food Restaurants, which presents a beautiful analogy for the Node.js model compared to a thread-based model.

“Perfect for data-intensive real-time applications that run across distributed devices”

The simplified asynchronous model used by Node.js naturally makes it suitable for data-intensive and real-time applications. A lot of heavy lifting can be going on in the background with no effect on the user experience.

As for running across distributed devices, this statement suggests that horizontal scaling, or ‘scaling out’, is straightforward with Node.js. As far as I can tell, scaling out is not any easier with Node.js than with other web server architectures. There is a Node.js module, node-http-proxy, which allows you to use this single technology across your system, however you could just as easily use an alternative load-balancing technology such as nginx.

In stating that Node.js is ‘perfect’ for distributed systems, it may be that the Node.js website is really just telling us that it can handle distributed systems.

Final Words

After this little exploration of Node.js, I have to say I am excited to learn more. Node.js is certainly a growing technology and anything which allows us to build faster and more scalable applications more easily gets my approval. Plus I love JavaScript. Now I just need to come up with a little pet project to explore Node.js some more.

Share Button