For a long time when I thought of server-side languages, JavaScript was not among them. Although it is largely one of the most popular programming languages in use today and is incredibly powerful, I thought of it as strictly a browser language — then I found Node.

Built in 2009, Node is an environment for server-side JavaScript. So what is Node? Well, the official definition from the site itself is as follows:

Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js’ package ecosystem, npm, is the largest ecosystem of open source libraries in the world. — Node.js Foundation

Cool. But what does any of that mean? Let’s break it down a bit.

Event-Driven Programming:

In Node, we work within an architecture known as the “Event Loop” — this is how Node handles high throughput scenarios by using a series of event listeners that execute callbacks upon detection of an event; these callbacks can be either synchronous or asynchronous. If this still sounds like basic JavaScript, great — it is. For any users of React.js, the following definition will sound extremely familiar:

Event-driven programming is application flow control that is determined by events or changes in state. — Trevor Norris; ‘Understanding the Node.js Event Loop’

Compared to Vanilla JavaScript as seen in the browser using event listeners like .onclick() or .onsubmit() , Node uses the EventEmitter module:

const EventEmitter = require('events');

Node objects (i.e. Socket, Server, streams, HTTP requests, etc.) emit events through instances of the Event Emitter . It is important to note that Node’s built-in modules inherit from EventEmitter whereas custom modules will need to be classes that extend it. Below is a common example:

class MyEmitter extends EventEmitter {

//enter some emitter functionality here

}

We then instantiate emitter objects and use the .emit function to indicate the event to be emitted. For example, we can use a custom event emitter, WithLog , and the .on() listener to listen for a console log and, upon detecting the desired string logged (i.e. ‘Hello World’) it will execute a callback function (i.e. console.log(‘Hello to You Too!’).

It is this event-driven programming that is one of the main facets of why Node is known as faster than conventional server-side languages such as Ruby, Python or Perl.

At this point we should make it absolutely clear that although Node facilitates concurrency through asynchronous events and is highly scalable, it is still considered to be single-threaded. As discussed in earlier posts, concurrency is only about building structures to facilitate parallelism and multithreading. This can be seen as a drawback when compared to other languages that support multithreading natively (such as Ruby). With that said, lets explore this concurrency further with the other major facet of Node:

Non-Blocking I/O Model:

Node.js is built on top of several dependencies. Primarily, we will refer to libuv, a cross-platform library that abstracts asynchronous input/output calls supported by the operating system of the device it is running on. This allows Node to handle thousands of asynchronous calls in a single stream of execution with the semblance of synchronicity — again, not parallelism.

You can picture it like an octopus that is really, really good at multitasking. It has a finite number of arms but can split its attention and coordinate actions and timing between various tasks without missing a step.

When we refer to non-blocking, we mean an algorithm which can execute its function without holding up the thread and blocking other tasks from being executed until it is finished; this is the beauty of async functions that makes JavaScript faster and more powerful than conventional server-side programming languages.

As a very reductive example, let’s say we were baking a tiered layer cake with one workstation and an oven big enough for only one tier pan at a time. It is an incredibly complex process requiring attention, timing and the coordination of several steps. After making the batter for the cake and placing the bottom tier pan in the oven to bake, we now have to wait a while — BUT, we’ve also got a messy workstation of batter-y bowls, spoons, broken eggshells etc. Since we only have so much workspace and we know that once the cake is done baking we’ll need to use the space to frost decorate the cake and we’ll need to put the next pan in, we can save ourselves some time by multitasking. We’ll place the first tier into the oven to bake and while baking, clean up the workstation, wash the dishes and leave out only the necessary decorating and frosting materials. Once the tier is completed, we’ll insert the next tier and repeat the process until all is cleaned and completed!

Much in the same fashion, this is how Node handles and executes events for server-side application. This also allows us to maximize CPU and memory usage.

So what is the difference between Node.js and JavaScript? Remember, JavaScript is a programming language. Node is a JavaScript run-time environment using the V8 engine (Google Chrome’s engine) and several library dependencies to handle event-driven non-blocking I/O. Whereas in a browser we use JavaScript to modify a webpage (text, graphics, stylesheets, etc), Node enables us to use JavaScript outside of the browser to create shell scripts and run on hardware so we can create servers or manipulate files.