Tag Archives: server-side javascript

Server Side Javascript Continued – Node.js (plus example)

1 Jul

Update: Node’s APIs have change quite a bit since this post was made. Check out the latest stuff at nodejs.org!

In my previous post on server-side javascript (SSJ) I took a quick look at Jack, a project that aims to implement the Rack/WSGI pattern for javascript. I still think this approach is great as it opens the door for more traditional Rails/Django-esque frameworks for SSJ.

But, lets face it, the next gen web is all about real-time interactivity, and current popular environments and servers just aren’t ideal for that. It’s not their fault, up until recently we only cared about getting that request handled and out the door as quickly as possible with nothing shared between requests. Unfortunately, it’s no longer just about number of requests/sec — we now need high concurrency, long-lasting connections, and shared persistence over these connections.

Node.js

Enter node.js – a high performance javascript project built ontop of Google’s V8 runtime. From the author’s description:

Node’s goal is to provide an easy way to build scalable network programs. … Each connection is only a small heap allocation. This is in contrast to today’s more common model where OS threads are employed for concurrency.

Nice, but does this pan out in implementation? After spending a few days with Node, I truly believe that this will be the go-to project for the future of the real-time web.

A Simple Game Lobby

Let’s take a look at a simple example I put together. The following is a very basic game lobby that is based on a more complex project I’m working on with node. (You can checkout this script from github as well).

The script accepts new players through a url like /join?player=joebob. Then, the client can long-poll the URL /wait and receive a notification in real-time when new players join!

First, lets define a couple of Arrays that will hold our persistence in-memory.

// our in-memory list of player
var players = [];

// our in-memory list of players waiting
var waiting = [];

Next, lets define a set of URLs our server will respond to. Notice that the /wait response does not take place immediately. Instead, the response is captured in a callback function that is held in-memory until it is called. These callbacks are called whenever a new player hits the /join URL.

// define a set of paths that respond to requests
var paths = {

  /**
   * Requests to /join add players to our
   * player list, and fire off a notification
   * to all our waiting players
   **/
  "/join": function(req, res) {

    // extract the player from the request
    var newPlayer = req.uri.params.player;

    // respond to this request with a list of players
    // already in the lobby
    server.respond(200, players);

    // add this player to list of players
    players.push(newPlayer);

    // notify all of our waiting players that
    // a new player has joined
    while(waiting.length > 0) {
      waiting.shift().callback.apply(this, [newPlayer]);
    }
  },

  /**
   * Requests to /wait holds the connection
   * open until another player joins
   **/
  "/wait": function(req, res) {

    // define our waiting player and the notification
    // callback to trigger when another player joins
    var waitingPlayer = {
      "player": req.uri.params.player,
      "callback": function(newPlayer) {
         server.respond(200, newPlayer);
       }
    };

    waiting.push(waitingPlayer);
  }
};

Finally, we define our server. We tell the server to map requests to the paths we defined above, and to listen on port 8000.

// Define a new HTTP Server
var server = node.http.createServer(function (req, res) {

  // tell our server to look at the paths definition above
  // for a responder to the request
  paths[req.uri.path].apply(this, [req, res]);

  // respond to a request
  function respond(status, obj) {
    var body = JSON.stringify(obj);
    res.sendHeader(status, [ ["Content-Type", "text/json"]
                         , ["Content-Length", body.length]
                         ]);
    res.sendBody(body);
    res.finish();
  }
});
server.listen(8000);
puts("The game lobby has started!");

To run the script, first download and build node, and then download this script from my repo. Execute the script with:

> node gamelobby.js

The Brave New World of Server-Side Javascript

8 Jun

Not the B Team

Not the B Team

Every once in a while I hear whispers of server-side javascript and I get just as excited as the next person. But, I’ll admit that until recently a phrase like “Javascript on Rails” was on the same level as a phrase like “McGyver vs. The A Team – The Movie.” Fictonal. But awesome in theory.

(Don’t worry, they eventually join forces in the sequel)

But what about Jaxer?

My limited experience with server-side javascript (SSJ) has been through Jaxer, from Aptana.  It touts some cool functionality, like loading the DOM server-side and built-in database drivers for MySQL, with the former allowing for DOM manipulation and integration with libraries like jQuery.

The extremely original Gear logo

Ubiquitous "Gear" Logo

But, in its attempts to blur the lines between client and server execution, Jaxer has made sacrifices in its extensibility. It is meant to be plugged into another system. For instance, I don’t know of an easy way to expose data through a RESTful JSON/XML API (like so many sites are doing nowadays) using Jaxer alone.

What I’m really looking for in SSJ is something akin to the ecosystem surrounding languages like Ruby and Python.  That’s why I was pleasantly surprised to stumble accross a few projects that aim to do just that.

Narwhal – Javascript Standard Library and Interactive Console

The foundation of any good ecosystem is a standard library.  Enter Narwhal, “a flexible javascript standard library.”

There are a lot of things to like about this project, but the primary benefit is its attempts to play nice with multiple javascript runtimes like Rhino and V8cgi.  Also, this project is embracing Mozilla’s ServerJS standard which I think is important for its longevity and interoperability.

Setup is a breeze, you can simply clone the project from github:

git clone git://github.com/tlrobinson/narwhal.git

Once you add narwhal/bin to your $PATH, you can use the convenient symlink js to enter an interactive javascript console similar to irb or python.

Jack – Javascript’s “Rack”

Interestingly enough, Narwhal came into existence as it’s author, Tom Robinson, was working on Jack.

JSGI is a webserver interface for JavaScript inspired by Ruby’s Rack (http://rack.rubyforge.org/) and Python’s WSGI (http://www.wsgi.org/).

Jack is an implementation of JSGI compatible handlers (to connect to web servers), middleware (to intercept and manipulate requests to add functionality), and utilities (to make using JSGI easier).

Setup is also breezy. Simply clone Jack into the same directory you cloned Narwhal into:

git clone git://github.com/tlrobinson/jack.git

Since you’ve already added narwhal’s bin directory to your path, lets just make a symlink to jackup from there.

From your narwhal/bin directory:
ln -s [path/to/jack]/bin/jackup jackup

Run jackup -h for usage.

So, what’s next? Where’s Javascript on Rails?

With Narwhal and Jack, you can start writing basic web apps. Looking at the example.js script in jack/examples we can see the basic request/response structure. Looks familiar huh?

var Jack = require("jack");

var map = {};

// an extremely simple Jack application
map["/hello"] = function(env) {
    return [200, {"Content-Type":"text/plain"}, ["Hello from " + env["SCRIPT_NAME"]]];
}

// apply the URLMap
var app = Jack.ContentLength(Jack.URLMap(map));
//...

While these two pieces are a good start to a vibrant server-side javascript ecosystem, there’s still a long ways to go to before it’ll be on par with Ruby and Python.

What SSJ needs is its Django/Pylons/Rails/Merb. There are a couple of projects I’ve found in the wild that are using Jack and Narwhal, but they appear to still be in very rapid flux.

Nitro

Nitro provides a library of carefully designed middleware and utilities for creating scalable, standards-compliant Web Applications with JavaScript.

Helma NG

Helma NG consists of several components that can be used together or alone:

1) A compact JavaScript runtime environment based on Mozilla Rhino. It adds
to Rhino a reloading module system that is compatible to the ServerJS
Securable Module proposal.

2) An interactive shell with support for autocompletion and history.

3) A module library implemented in JavaScript, covering basic functionality
such as extensions to the built-in objects, file I/O, logging, persistence,
client and server side HTTP support and more.