Looking Outside Ruby: Node.js

Tweet

In this, the latest in the Looking Outside Ruby series, we’re going to have a look at server-side JavaScript with Node.

What is Node?

Node is a set of libraries that enable JavaScript to run outside the browser, where the JavaScript in question is the V8 engine from Chrome. It’s main aim is to make it simple and easy to build network clients and servers. Node was started back in 2009 by Ryan Dahl and the project is currently sponsored by Joyent, his employer.

Why use it?

In a nutshell: speed and scalability. The V8 JavaScript engine that is at the heart of Node is known for it’s speed, and the “evented I/O” approach used by Node makes it scalable and able to handle many concurrent connections with ease.

Evented I/O

Node uses an event loop architecture, the design of which was partly influenced by Ruby’s Event Machine. If you’re not familiar with event loops, they’re defined on Wikipedia as:

a programming construct that waits for and dispatches events or messages in a program. It works by polling some internal or external “event provider”, which generally blocks until an event has arrived, and then calls the relevant event handler (“dispatches the event”)….The event loop almost always operates asynchronously with the message originator.

Basically, Node is constantly checking for events occurring, be that receiving a HTTP request or accessing a file on the disk. When a given event fires, it’s event-handling callback function is executed.

This type of event handling happens to us a lot in everyday life. How many times have you phoned someone and had to leave a message for them to call you back? While your waiting for them to callback you’re free to get on with other things.

One of the examples used in Ryan Dahl’s slides from his 2009 talk at JSConf.eu looks at database access:

var result = db.query("select * from T");
// use result

The pertinent question that is then asked is: what is your software doing while it queries the database? The answer is: usually nothing. The same code implemented in an event loop might look something like this:

db.query("select...", function(result) {
    // use result
});

The program can return to the event loop straight away and doesn’t have to wait for the database query to finish. When it does finish the event loop will dispatch the callback function.

Node runs in a single thread, just as JavaScript runs in a single thread in the browser. As such, you should try to make sure that all I/O in your Node code is non-blocking – you don’t want to be blocking the event loop by doing some CPU-intensive computations or synchronous I/O. Fortunately, Node comes with a set of core modules that provide a non-blocking interfaces to access things such as file and network resources.

Installation

Node source code is available on OS X and Linux, and there’s an node.exe you can download for Windows. You can install node via a package manager; at the time of writing packages exist for Debian, Ubuntu, openSUSE, Arch Linux, homebrew and macports on OS X, and chocolatey on Windows.

If you want to build Node yourself on OS X or Linux you’ll need to fire up a command-line and type the following:

curl -O http://nodejs.org/dist/node-v0.4.12.tar.gz
tar xzvf node-v0.4.12.tar.gz
cd node-v0.4.12.tar.gz
./configure --prefix=/usr/local/node
make
make install

NB Here we’re installing Node into /usr/local but, if you’re comfortable with building packages from source code, feel free to change this as you see fit.

Once Node is installed, set your $NODE_PATH environment variable so that Node knows where to look for modules:

echo 'export NODE_PATH=/opt/node:/opt/node/lib/node_modules' >> ~/.bashrc # ~/.bash_profile or ~/.profile on some systems

If /usr/local/node/bin isn’t already in your $PATH you can add it like so:

echo 'export PATH=$PATH:/opt/node/bin' >> ~/.bashrc # ~/.bash_profile or ~/.profile on some systems

Then type in the following to reload your new $PATH:

. ~/.bashrc # ~/.bash_profile or ~/.profile on some systems

Writing code

Let’s start by looking at the canonical “hello world” program, this time in the form of a web server:

var http = require('http');

http.createServer(function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello, World!');
}).listen(4567, '127.0.0.1');
console.log('Server running at http://127.0.0.1:4567');

You can either save this code in a file called something like server.jsand run it by typing node server.js in your terminal, or alternatively just type node at the command-prompt to start node in interactive mode – the equivalent of Ruby’s irb – and copy-and-paste the code into the terminal. In this code we’re:

  1. Importing the http module using the require function
  2. Calling the http module’s createServer function and passing it a callback function; this function will be fired every time Node receives a new connection
  3. Telling Node which port and IP address we want our server to run / listen on
  4. Logging a message to the console so that we know our server is up and running

Remember earlier when we mentioned Node’s scalability?

the “hello world” web server…many client connections can be handled concurrently. Node tells the operating system (through epoll, kqueue, /dev/poll, or select) that it should be notified when a new connection is made, and then it goes to sleep. If someone new connects, then it executes the callback. Each connection is only a small heap allocation.
– from http://nodejs.org/#about

Emitting and Handling your own Events

No matter how much you use Node’s core modules, there will come a time when you need to emit and handle your own – or someone else’s – custom events. Node comes with an EventEmitter class that helps us do this. The two main methods it has that we’re interested in here are on and emit. When wiring up and handling our custom events, we can inherit from EventEmitter to attach these methods to our code. Lets have a look at a simple server to illustrate this:

var util = require('util'),
        EventEmitter = require('events').EventEmitter;

var Server = function() {
    console.log('init');
};

util.inherits(Server, EventEmitter);
var s = new Server();

s.on('error', function() {
    console.log('error...');
});

...

s.emit('error');

In this example:

  1. We use the util module’s inherits method to make our Server class inherit from the EventEmitter
  2. We setup a callback function for the ‘error’ event by calling the now inherited on method
  3. Calling emit on our Server instance will cause the error callback function to fire

Node Modules

Node uses the CommonJS module system. The goal of CommonJS is to provide a common API for JavaScript on the server that can be used regardless of the JavaScript interpreter, so the same code that runs on Node can also be run without modification on Rhino. CommonJS also defines how modules can be loaded using require and how you need to make use of the exports object when writing your own modules.

If you look at the earlier example code, you’ll see that we used require to import some of the core modules. CommonJS stipulates that each module will have access to the require function, and that require should return the exported API of the module (more on that shortly). When you pass require the name of a module, you can either pass it the name of a ‘top-level’ module or a ‘relative’ module i.e. the module identifier starts with a . or ...

Now, what was meant by “exported API”? Well, CommonJS also states that each module will have access to the exports object, and you define your module’s API by explicitly adding functions and variables to it; any functions and variables that aren’t added to exports remain private to the module.

We can illustrate this by writing our own module, jedimindtrick. As Node uses a one-file-per-module approach, save the code below in a file called jedimindtrick.js:

// jedimindtrick.js
var droid1 = 'R2-D2',
    droid2 = 'C-3PO';

exports.mindTrick = function(d1, d2) {
    if (droid1 === d1 && droid2 === d2) {
        console.log("These aren't the droids you're looking for");
    }
}

moveAlong = function() {
    console.log("Move along...move along");
}

Then, at the command-line, change directory so that you’re in the same folder where you just saved jedimindtrick.js, type node and hit <Enter> to fire up Node’s interactive mode, and type in following:

var jedi = require('./jedimindtrick');
jedi.mindTrick('R2-D2', 'C-3PO');
jedi.moveAlong();

In this code we’re passing the relative path to our module to require, calling the exported function mindTrick, then attempting to call the moveAlong function. But, as this wasn’t added to the exports object in our module, we’ll cause a TypeError: Object [object Object] has no method 'moveAlong'.

Hosting

Finally, a quick word on hosting. The Node wiki has a list of hosting providers. The good news for Ruby programmers is that Node hosting is provided by Heroku.

Well, that was a quick look at Node. We’ve looked at what Node is and the potential advantages it offers, how you can install it, been through some short code examples and had a quick look at Node modules and how you can write your own. It is by no means a comprehensive guide, but hopefully, if you haven’t yet had a look at Node, it’ll have encouraged you to do so.

Further Reading

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://xmlsoap.dk Michael

    Ever since JScript MS, I have sought this …

    I will try to setup a lab NOT using IIS – but Nodejs

    Thanks Mike

  • http://www.udgwebdev.com Caio Ribeiro Pereira

    Just to complement, look some post on my blog too, there are many post about Node.js.

    http://www.udgwebdev.com/category/nodejs/

    Bye!