by Anders Janmyr - Dynamic languages
Node.js is a set of asynchronous libraries, built on top of the Google V8 Javascript engine. Node is used for server side development in Javascript. Do you feel the rush of the 90′s coming through your head. It is not the revival of LiveWire, Node is a different beast. Node is a single threaded process, focused on doing networking right. Right, in this case, means without blocking I/O.
All the libraries built for Node use non-blocking I/O. This is a really cool feature, which allows the single thread in Node to serve thousands of request per second. It even lets you run multiple servers in the same thread. Check out the performance characteristics of Nginx and Apache that utilize the same technique.

The graph for memory usage is even better.

Read more about it at the Web Faction Blog
OK, so what’s the catch? The catch is that all code that does I/O, or
anything slow at all, has to be called in an asynchronous style.
|
1 2 3 4 5 6 7 8 9 |
<tt><i><font color="#9A1900">// Synchronous</font></i> <b><font color="#0000FF">var</font></b> result <font color="#990000">=</font> db<font color="#990000">.</font><b><font color="#000000">query</font></b><font color="#990000">(</font><font color="#FF0000">"select * from T"</font><font color="#990000">);</font> <i><font color="#9A1900">// Use result</font></i> <i><font color="#9A1900">// Asynchronous</font></i> db<font color="#990000">.</font><b><font color="#000000">query</font></b><font color="#990000">(</font><font color="#FF0000">"select * from T"</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b> <font color="#990000">(</font>result<font color="#990000">)</font> <font color="#FF0000">{</font> <i><font color="#9A1900">// Use result</font></i> <font color="#FF0000">}</font><font color="#990000">);</font> </tt> |
So, all libraries that deal with IO has to be re-implemented with this
style of programming. The good news is that even though Node has only
been around for a couple of years, there are more than 1800 libraries
available. The libraries are of varying quality but the popularity of
Node shows good promise to deliver high-quality libraries for anything
that you can imagine.
Node is definitely not the first of its kind. The non-blocking
select() loop, that is at the heart of Node, dates back to 1983.
Twisted appeared in Python (2002) and EventMachine in Ruby (2003).
This year a couple of newcomers appeared.
Goliath, which builds on EventMachine, and uses fibers to allow us to program in an synchronous style even though it is asynchronous under the hood.
And, the Async Framework in
.Net, which enhances the compiler with the keywords async and await to allow for very elegant asynchronous programming.
This example uses OSX as an example platform, if you use something else
you will have to google for instructions.
|
1 2 3 4 5 6 7 8 9 10 11 |
<tt><i><font color="#9A1900"># Install Node using Homebrew</font></i> $ brew install node <font color="#990000">==></font> Downloading http<font color="#990000">:</font>//nodejs<font color="#990000">.</font>org/dist/node-v<font color="#993399">0.4</font><font color="#990000">.</font><font color="#993399">7</font><font color="#990000">.</font>tar<font color="#990000">.</font>gz <i><font color="#9A1900">######################################################################## 100.0%</font></i> <font color="#990000">==></font> <font color="#990000">.</font>/configure --prefix<font color="#990000">=</font>/usr/local/Cellar/node<font color="#990000">/</font><font color="#993399">0.4</font><font color="#990000">.</font><font color="#993399">7</font> <font color="#990000">==></font> make install <font color="#990000">==></font> Caveats Please add /usr/local/lib/node to your NODE_PATH environment variable to have node libraries picked up<font color="#990000">.</font> <font color="#990000">==></font> Summary /usr/local/Cellar/node<font color="#990000">/</font><font color="#993399">0.4</font><font color="#990000">.</font><font color="#993399">7</font><font color="#990000">:</font> <font color="#993399">72</font> files<font color="#990000">,</font> <font color="#993399">7</font><font color="#990000">.</font>5M<font color="#990000">,</font> built <b><font color="#0000FF">in</font></b> <font color="#993399">1.2</font> minutes </tt> |
When installed you have access to the node command-line command. When
invoked without arguments, it start a REPL.
|
1 2 3 4 5 6 7 8 |
<tt>$ node <font color="#990000">></font> <b><font color="#000000">function hello</font></b><font color="#990000">(</font>name<font color="#990000">)</font> { <font color="#990000">...</font> <b><font color="#0000FF">return</font></b> <font color="#FF0000">'hello '</font> <font color="#990000">+</font> name<font color="#990000">;</font> <font color="#990000">...</font> } <font color="#990000">></font> hello<font color="#990000">(</font><font color="#FF0000">'tapir'</font><font color="#990000">)</font> <font color="#FF0000">'hello tapir'</font> <font color="#990000">></font> </tt> |
When invoked with a script it runs the script.
|
1 2 3 4 5 6 7 |
<tt><i><font color="#9A1900">// hello.js</font></i> <b><font color="#000000">setTimeout</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font> console<font color="#990000">.</font><b><font color="#000000">log</font></b><font color="#990000">(</font><font color="#FF0000">'Tapir'</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">,</font> <font color="#993399">2000</font><font color="#990000">);</font> console<font color="#990000">.</font><b><font color="#000000">log</font></b><font color="#990000">(</font><font color="#FF0000">'Hello'</font><font color="#990000">);</font> </tt> |
|
1 2 3 4 5 |
<tt>$ node hello<font color="#990000">.</font>js Hello <font color="#990000">...</font> Tapir </tt> |
As I mentioned above, Node is focused on networking. That means it
should be easy to write networking code. Here is a simple echo server.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
<tt><i><font color="#9A1900">// Echo Server</font></i> <b><font color="#0000FF">var</font></b> net <font color="#990000">=</font> <b><font color="#000000">require</font></b><font color="#990000">(</font><font color="#FF0000">'net'</font><font color="#990000">);</font> <b><font color="#0000FF">var</font></b> server <font color="#990000">=</font> net<font color="#990000">.</font><b><font color="#000000">createServer</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">(</font>socket<font color="#990000">)</font> <font color="#FF0000">{</font> socket<font color="#990000">.</font><b><font color="#000000">on</font></b><font color="#990000">(</font><font color="#FF0000">'data'</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>data<font color="#990000">)</font> <font color="#FF0000">{</font> console<font color="#990000">.</font><b><font color="#000000">log</font></b><font color="#990000">(</font>data<font color="#990000">.</font><b><font color="#000000">toString</font></b><font color="#990000">());</font> socket<font color="#990000">.</font><b><font color="#000000">write</font></b><font color="#990000">(</font>data<font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> server<font color="#990000">.</font><b><font color="#000000">listen</font></b><font color="#990000">(</font><font color="#993399">4000</font><font color="#990000">);</font> </tt> |
And here is a simple HTTP server.
|
1 2 3 4 5 6 7 8 9 10 11 |
<tt><i><font color="#9A1900">// HTTP Server</font></i> <b><font color="#0000FF">var</font></b> http <font color="#990000">=</font> <b><font color="#000000">require</font></b><font color="#990000">(</font><font color="#FF0000">'http'</font><font color="#990000">);</font> <b><font color="#0000FF">var</font></b> web <font color="#990000">=</font> http<font color="#990000">.</font><b><font color="#000000">createServer</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">(</font>request<font color="#990000">,</font> response<font color="#990000">)</font> <font color="#FF0000">{</font> response<font color="#990000">.</font><b><font color="#000000">writeHead</font></b><font color="#990000">(</font><font color="#993399">200</font><font color="#990000">,</font> <font color="#FF0000">{</font> <font color="#FF0000">'Content-Type'</font><font color="#990000">:</font> <font color="#FF0000">'text/plain'</font> <font color="#FF0000">}</font><font color="#990000">);</font> response<font color="#990000">.</font><b><font color="#000000">end</font></b><font color="#990000">(</font><font color="#FF0000">'Tapirs are beautiful!</font><font color="#CC33CC">n</font><font color="#FF0000">'</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> web<font color="#990000">.</font><b><font color="#000000">listen</font></b><font color="#990000">(</font><font color="#993399">4001</font><font color="#990000">);</font> </tt> |
Quite similar. A cool thing is that the servers can be started from the
same file and node will, happily, serve both HTTP and echo requests from
the same thread without any problems. Let’s try them out!
|
1 2 3 4 5 6 7 8 9 |
<tt><i><font color="#9A1900"># curl the http service</font></i> $ curl localhost<font color="#990000">:</font><font color="#993399">4001</font> Tapirs are beautiful<font color="#990000">!</font> <i><font color="#9A1900"># use netcat to send the string to the echo server</font></i> $ echo <font color="#FF0000">'Hello beautiful tapir'</font> <font color="#990000">|</font> nc localhost <font color="#993399">4000</font> Hello beautiful tapir </tt> |
Node comes with a selection of built in modules. Ryan Dahl says that
they try to keep the core small, but even so the built-in modules cover
a lot of useful functionality.
Here is an example of a simple module.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<tt><i><font color="#9A1900">// module tapir.js</font></i> <i><font color="#9A1900">// require another module</font></i> <b><font color="#0000FF">var</font></b> util <font color="#990000">=</font> <b><font color="#000000">require</font></b><font color="#990000">(</font><font color="#FF0000">'util'</font><font color="#990000">);</font> <b><font color="#0000FF">function</font></b> <b><font color="#000000">eat</font></b><font color="#990000">(</font>food<font color="#990000">)</font> <font color="#FF0000">{</font> util<font color="#990000">.</font><b><font color="#000000">log</font></b><font color="#990000">(</font><font color="#FF0000">'eating '</font><font color="#990000">+</font> food<font color="#990000">);</font> <font color="#FF0000">}</font> <i><font color="#9A1900">// export a function</font></i> exports<font color="#990000">.</font>eat <font color="#990000">=</font> eat<font color="#990000">;</font> </tt> |
As you can see it looks like a normal Javascript file and it even looks
like it has global variables. It doesn’t. When a module is loaded it is
wrapped in code, similar to this.
|
1 2 3 4 5 6 7 |
<tt><b><font color="#0000FF">var</font></b> module <font color="#990000">=</font> <font color="#FF0000">{</font> exports<font color="#990000">:</font> <font color="#FF0000">{}}</font><font color="#990000">;</font> <font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">(</font>module<font color="#990000">,</font> exports<font color="#990000">)</font><font color="#FF0000">{</font> <i><font color="#9A1900">// module code from file</font></i> <font color="#990000">...</font> <font color="#FF0000">}</font><font color="#990000">)(</font>module<font color="#990000">,</font> module<font color="#990000">.</font>exports<font color="#990000">);</font> </tt> |
As you can see the code is wrapped in a function and an empty object
with an export property is sent into it. This is used by the file to
export only the functions that it want to publish.
The require function works in symphony with the module and it returns
the exported functions to the caller.
To allow simple handling of third-party packages, Node uses npm. It
can be installed like this:
|
1 2 3 4 |
<tt>$ curl http<font color="#990000">:</font>//npmjs<font color="#990000">.</font>org/install<font color="#990000">.</font>sh <font color="#990000">|</font> sh <font color="#990000">...</font> </tt> |
And used like this:
|
1 2 3 4 5 6 7 8 |
<tt>$ npm install -g express mime@<font color="#993399">1.2</font><font color="#990000">.</font><font color="#993399">1</font> /usr/local/lib/node_modules/express/node_modules/mime connect@<font color="#993399">1.4</font><font color="#990000">.</font><font color="#993399">0</font> /usr/local/lib/node_modules/express/node_modules/connect qs@<font color="#993399">0.1</font><font color="#990000">.</font><font color="#993399">0</font> /usr/local/lib/node_modules/express/node_modules/qs /usr/local/bin/express -<font color="#990000">></font> /usr/local/lib/node_modules/express/bin/express express@<font color="#993399">2.3</font><font color="#990000">.</font><font color="#993399">2</font> /usr/local/lib/node_modules/express </tt> |
As you can see, installing a module also installs its dependencies. This
works because a module can be package with meta-data, like so:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<tt><i><font color="#9A1900">// express/package.json</font></i> <font color="#FF0000">{</font> <font color="#FF0000">"name"</font><font color="#990000">:</font> <font color="#FF0000">"express"</font><font color="#990000">,</font> <font color="#FF0000">"description"</font><font color="#990000">:</font> <font color="#FF0000">"Sinatra inspired web development framework"</font><font color="#990000">,</font> <font color="#FF0000">"version"</font><font color="#990000">:</font> <font color="#FF0000">"2.3.2"</font><font color="#990000">,</font> <font color="#FF0000">"author"</font><font color="#990000">:</font> <font color="#FF0000">"TJ Holowaychuk <tj@vision-media.ca>"</font><font color="#990000">,</font> <font color="#FF0000">"contributors"</font><font color="#990000">:</font> <font color="#990000">[</font> <font color="#FF0000">{</font> <font color="#FF0000">"name"</font><font color="#990000">:</font> <font color="#FF0000">"TJ Holowaychuk"</font><font color="#990000">,</font> <font color="#FF0000">"email"</font><font color="#990000">:</font> <font color="#FF0000">"tj@vision-media.ca"</font> <font color="#FF0000">}</font><font color="#990000">,</font> <font color="#FF0000">{</font> <font color="#FF0000">"name"</font><font color="#990000">:</font> <font color="#FF0000">"Guillermo Rauch"</font><font color="#990000">,</font> <font color="#FF0000">"email"</font><font color="#990000">:</font> <font color="#FF0000">"rauchg@gmail.com"</font> <font color="#FF0000">}</font> <font color="#990000">],</font> <font color="#FF0000">"dependencies"</font><font color="#990000">:</font> <font color="#FF0000">{</font> <font color="#FF0000">"connect"</font><font color="#990000">:</font> <font color="#FF0000">">= 1.4.0 < 2.0.0"</font><font color="#990000">,</font> <font color="#FF0000">"mime"</font><font color="#990000">:</font> <font color="#FF0000">">= 0.0.1"</font><font color="#990000">,</font> <font color="#FF0000">"qs"</font><font color="#990000">:</font> <font color="#FF0000">">= 0.0.6"</font> <font color="#FF0000">}</font><font color="#990000">,</font> <font color="#FF0000">"keywords"</font><font color="#990000">:</font> <font color="#990000">[</font><font color="#FF0000">"framework"</font><font color="#990000">,</font> <font color="#FF0000">"sinatra"</font><font color="#990000">,</font> <font color="#FF0000">"web"</font><font color="#990000">,</font> <font color="#FF0000">"rest"</font><font color="#990000">,</font> <font color="#FF0000">"restful"</font><font color="#990000">],</font> <font color="#FF0000">"repository"</font><font color="#990000">:</font> <font color="#FF0000">"git://github.com/visionmedia/express"</font><font color="#990000">,</font> <font color="#FF0000">"main"</font><font color="#990000">:</font> <font color="#FF0000">"index"</font><font color="#990000">,</font> <font color="#FF0000">"bin"</font><font color="#990000">:</font> <font color="#FF0000">{</font> <font color="#FF0000">"express"</font><font color="#990000">:</font> <font color="#FF0000">"./bin/express"</font> <font color="#FF0000">}</font><font color="#990000">,</font> <font color="#FF0000">"engines"</font><font color="#990000">:</font> <font color="#FF0000">{</font> <font color="#FF0000">"node"</font><font color="#990000">:</font> <font color="#FF0000">">= 0.4.1 < 0.5.0"</font> <font color="#FF0000">}</font> <font color="#FF0000">}</font> </tt> |
The package.json contains information about who made the module, its
dependencies, along with some additional information to enable better
searching facilities.
Npm installs the modules from a common
respository, which contains more than 1800
modules.
Express is probably the most used of all third-party modules. It is
a Sinatra clone and it is very good, just like Sinatra.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<tt><i><font color="#9A1900">// Create a server</font></i> <b><font color="#0000FF">var</font></b> app <font color="#990000">=</font> express<font color="#990000">.</font><b><font color="#000000">createServer</font></b><font color="#990000">();</font> app<font color="#990000">.</font><b><font color="#000000">listen</font></b><font color="#990000">(</font><font color="#993399">4000</font><font color="#990000">);</font> <i><font color="#9A1900">// Mount the root (/) and redirect to index</font></i> app<font color="#990000">.</font><b><font color="#000000">get</font></b><font color="#990000">(</font><font color="#FF0000">'/'</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>req<font color="#990000">,</font> res<font color="#990000">)</font> <font color="#FF0000">{</font> res<font color="#990000">.</font><b><font color="#000000">redirect</font></b><font color="#990000">(</font><font color="#FF0000">'/index.html'</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> <i><font color="#9A1900">// Handle a post to /quiz</font></i> app<font color="#990000">.</font><b><font color="#000000">post</font></b><font color="#990000">(</font><font color="#FF0000">'/quiz'</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>req<font color="#990000">,</font> res<font color="#990000">)</font> <font color="#FF0000">{</font> res<font color="#990000">.</font><b><font color="#000000">send</font></b><font color="#990000">(</font>quiz<font color="#990000">.</font><b><font color="#000000">create</font></b><font color="#990000">().</font>id<font color="#990000">.</font><b><font color="#000000">toString</font></b><font color="#990000">());</font> <font color="#FF0000">}</font><font color="#990000">);</font> </tt> |
Express uses Connect to handle middleware. Middleware is like Rack
but for Node (No wonder that Node is nice to work with when it borrows
its ideas from Ruby :)
|
1 2 3 4 5 6 7 8 9 10 11 |
<tt><b><font color="#000000">connect</font></b><font color="#990000">(</font> <i><font color="#9A1900">// Add a logger</font></i> connect<font color="#990000">.</font><b><font color="#000000">logger</font></b><font color="#990000">()</font> <i><font color="#9A1900">// Serve static file from the current directory</font></i> <font color="#990000">,</font> connect<font color="#990000">.</font><b><font color="#0000FF">static</font></b><font color="#990000">(</font>__dirname<font color="#990000">)</font> <i><font color="#9A1900">// Compile Sass and Coffescript files, on the fly</font></i> <font color="#990000">,</font> connect<font color="#990000">.</font><b><font color="#000000">compiler</font></b><font color="#990000">(</font><font color="#FF0000">{</font>enable<font color="#990000">:</font> <font color="#990000">[</font><font color="#FF0000">'sass'</font><font color="#990000">,</font> <font color="#FF0000">'coffeescript'</font><font color="#990000">]</font><font color="#FF0000">}</font><font color="#990000">)</font> <i><font color="#9A1900">// Profile all requests</font></i> <font color="#990000">,</font> connect<font color="#990000">.</font><b><font color="#000000">profiler</font></b><font color="#990000">()</font> <font color="#990000">).</font><b><font color="#000000">listen</font></b><font color="#990000">(</font><font color="#993399">3000</font><font color="#990000">);</font> </tt> |
Another popular library is Socket.IO. It handles the usual socket
variants, such as WebSocket, Comet, Flash Sockets, etc…
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<tt><b><font color="#0000FF">var</font></b> http <font color="#990000">=</font> <b><font color="#000000">require</font></b><font color="#990000">(</font><font color="#FF0000">'http'</font><font color="#990000">);</font> <b><font color="#0000FF">var</font></b> io <font color="#990000">=</font> <b><font color="#000000">require</font></b><font color="#990000">(</font><font color="#FF0000">'socket.io'</font><font color="#990000">);</font> server <font color="#990000">=</font> http<font color="#990000">.</font><b><font color="#000000">createServer</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">(</font>req<font color="#990000">,</font> res<font color="#990000">)</font><font color="#FF0000">{</font><font color="#990000">...</font><font color="#FF0000">}</font><font color="#990000">);</font> server<font color="#990000">.</font><b><font color="#000000">listen</font></b><font color="#990000">(</font><font color="#993399">80</font><font color="#990000">);</font> <i><font color="#9A1900">// socket.io attaches to an existing server</font></i> <b><font color="#0000FF">var</font></b> socket <font color="#990000">=</font> io<font color="#990000">.</font><b><font color="#000000">listen</font></b><font color="#990000">(</font>server<font color="#990000">);</font> socket<font color="#990000">.</font><b><font color="#000000">on</font></b><font color="#990000">(</font><font color="#FF0000">'connection'</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>client<font color="#990000">)</font><font color="#FF0000">{</font> <i><font color="#9A1900">// new client is here!</font></i> client<font color="#990000">.</font><b><font color="#000000">on</font></b><font color="#990000">(</font><font color="#FF0000">'message'</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font><font color="#FF0000">{</font> ... <font color="#FF0000">}</font><font color="#990000">)</font> client<font color="#990000">.</font><b><font color="#000000">on</font></b><font color="#990000">(</font><font color="#FF0000">'disconnect'</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font><font color="#FF0000">{</font> ... <font color="#FF0000">}</font><font color="#990000">)</font> <font color="#FF0000">}</font><font color="#990000">);</font> </tt> |
MySql has a library for Node.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
<tt>client<font color="#990000">.</font><b><font color="#000000">query</font></b><font color="#990000">(</font> <font color="#FF0000">'SELECT * FROM '</font> <font color="#990000">+</font> TEST_TABLE<font color="#990000">,</font> <i><font color="#9A1900">// Note the callback style</font></i> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>err<font color="#990000">,</font> results<font color="#990000">,</font> fields<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">if</font></b> <font color="#990000">(</font>err<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">throw</font></b> err<font color="#990000">;</font> <font color="#FF0000">}</font> console<font color="#990000">.</font><b><font color="#000000">log</font></b><font color="#990000">(</font>results<font color="#990000">);</font> console<font color="#990000">.</font><b><font color="#000000">log</font></b><font color="#990000">(</font>fields<font color="#990000">);</font> client<font color="#990000">.</font><b><font color="#000000">end</font></b><font color="#990000">();</font> <font color="#FF0000">}</font> <font color="#990000">);</font> </tt> |
And Mongoose can be used for accessing MongoDB.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<tt><i><font color="#9A1900">// Declare the schema</font></i> <b><font color="#0000FF">var</font></b> Schema <font color="#990000">=</font> mongoose<font color="#990000">.</font>Schema <font color="#990000">,</font> ObjectId <font color="#990000">=</font> Schema<font color="#990000">.</font>ObjectId<font color="#990000">;</font> <b><font color="#0000FF">var</font></b> BlogPost <font color="#990000">=</font> <b><font color="#0000FF">new</font></b> <b><font color="#000000">Schema</font></b><font color="#990000">(</font><font color="#FF0000">{</font> author <font color="#990000">:</font> ObjectId <font color="#990000">,</font> title <font color="#990000">:</font> String <font color="#990000">,</font> body <font color="#990000">:</font> String <font color="#990000">,</font> date <font color="#990000">:</font> Date <font color="#FF0000">}</font><font color="#990000">);</font> <i><font color="#9A1900">// Use it</font></i> <b><font color="#0000FF">var</font></b> BlogPost <font color="#990000">=</font> mongoose<font color="#990000">.</font><b><font color="#000000">model</font></b><font color="#990000">(</font><font color="#FF0000">'BlogPost'</font><font color="#990000">);</font> <i><font color="#9A1900">// Save</font></i> <b><font color="#0000FF">var</font></b> post <font color="#990000">=</font> <b><font color="#0000FF">new</font></b> <b><font color="#000000">BlogPost</font></b><font color="#990000">();</font> post<font color="#990000">.</font>author <font color="#990000">=</font> <font color="#FF0000">'Stravinsky'</font><font color="#990000">;</font> instance<font color="#990000">.</font><b><font color="#000000">save</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b> <font color="#990000">(</font>err<font color="#990000">)</font> <font color="#FF0000">{</font> <i><font color="#9A1900">//</font></i> <font color="#FF0000">}</font><font color="#990000">);</font> <i><font color="#9A1900">// Find</font></i> BlogPost<font color="#990000">.</font><b><font color="#000000">find</font></b><font color="#990000">(</font><font color="#FF0000">{}</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b> <font color="#990000">(</font>err<font color="#990000">,</font> docs<font color="#990000">)</font> <font color="#FF0000">{</font> <i><font color="#9A1900">// docs.forEach</font></i> <font color="#FF0000">}</font><font color="#990000">);</font> </tt> |
Everytime a new platform makes its presence, it brings along a couple of
new templating languages and Node is no different. Along with the
popular ones from the Ruby world, like Haml and Erb (EJS in Node),
comes some new ones like Jade and some browser templating languages like
Mustache and jQuery templates. I’ll show examples of Jade and Mu
(Mustache for Node).
I like Jade, because it is a Javascript dialect of Haml and it seems
appropriate to use if I’m using Javascript on the server side.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<tt><font color="#990000">!!!</font> <font color="#993399">5</font> <b><font color="#000000">html</font></b><font color="#990000">(</font>lang<font color="#990000">=</font><font color="#FF0000">"en"</font><font color="#990000">)</font> head title<font color="#990000">=</font> pageTitle <b><font color="#000000">script</font></b><font color="#990000">(</font>type<font color="#990000">=</font><font color="#FF0000">'text/javascript'</font><font color="#990000">)</font> <b><font color="#0000FF">if</font></b> <font color="#990000">(</font>foo<font color="#990000">)</font> <font color="#990000">{</font> <b><font color="#000000">bar</font></b><font color="#990000">()</font> <font color="#990000">}</font> body h1 Jade <font color="#990000">-</font> node template engine <i><font color="#9A1900">#container</font></i> <font color="#990000">-</font> <b><font color="#0000FF">if</font></b> <font color="#990000">(</font>youAreUsingJade<font color="#990000">)</font> p You are amazing <font color="#990000">-</font> <b><font color="#0000FF">else</font></b> p Get on it<font color="#990000">!</font> </tt> |
I’m not really sure if I like Mustache or not, but I can surely see the
value of having a templating language which works both on the server side
and in the browser.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<tt><b><font color="#0000FF"><h1></font></b>{{header}}<b><font color="#0000FF"></h1></font></b> {{#bug}} {{/bug}} {{#items}} {{#first}} <b><font color="#0000FF"><li><strong></font></b>{{name}}<b><font color="#0000FF"></strong></li></font></b> {{/first}} {{#link}} <b><font color="#0000FF"><li><a</font></b> <font color="#009900">href</font><font color="#990000">=</font><font color="#FF0000">"{{url}}"</font><b><font color="#0000FF">></font></b>{{name}}<b><font color="#0000FF"></a></li></font></b> {{/link}} {{/items}} {{#empty}} <b><font color="#0000FF"><p></font></b>The list is empty.<b><font color="#0000FF"></p></font></b> {{/empty}} </tt> |
Node comes with assertions built in, and all testing frameworks build on
the Assert module, so it is good to know.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<tt>assert<font color="#990000">.</font><b><font color="#000000">ok</font></b><font color="#990000">(</font>value<font color="#990000">,</font> <font color="#990000">[</font>message<font color="#990000">]);</font> assert<font color="#990000">.</font><b><font color="#000000">equal</font></b><font color="#990000">(</font>actual<font color="#990000">,</font> expected<font color="#990000">,</font> <font color="#990000">[</font>message<font color="#990000">])</font> assert<font color="#990000">.</font><b><font color="#000000">notEqual</font></b><font color="#990000">(</font>actual<font color="#990000">,</font> expected<font color="#990000">,</font> <font color="#990000">[</font>message<font color="#990000">])</font> assert<font color="#990000">.</font><b><font color="#000000">deepEqual</font></b><font color="#990000">(</font>actual<font color="#990000">,</font> expected<font color="#990000">,</font> <font color="#990000">[</font>message<font color="#990000">])</font> assert<font color="#990000">.</font><b><font color="#000000">strictEqual</font></b><font color="#990000">(</font>actual<font color="#990000">,</font> expected<font color="#990000">,</font> <font color="#990000">[</font>message<font color="#990000">])</font> assert<font color="#990000">.</font><b><font color="#0000FF">throws</font></b><font color="#990000">(</font>block<font color="#990000">,</font> <font color="#990000">[</font>error<font color="#990000">],</font> <font color="#990000">[</font>message<font color="#990000">])</font> assert<font color="#990000">.</font><b><font color="#000000">doesNotThrow</font></b><font color="#990000">(</font>block<font color="#990000">,</font> <font color="#990000">[</font>error<font color="#990000">],</font> <font color="#990000">[</font>message<font color="#990000">])</font> assert<font color="#990000">.</font><b><font color="#000000">ifError</font></b><font color="#990000">(</font>value<font color="#990000">)</font> assert<font color="#990000">.</font><b><font color="#000000">fail</font></b><font color="#990000">(</font>actual<font color="#990000">,</font> expected<font color="#990000">,</font> message<font color="#990000">,</font> operator<font color="#990000">)</font> <i><font color="#9A1900">// Example</font></i> <i><font color="#9A1900">// assert.throws(function, regexp)</font></i> assert<font color="#990000">.</font><b><font color="#0000FF">throws</font></b><font color="#990000">(</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font> <b><font color="#0000FF">throw</font></b> <b><font color="#0000FF">new</font></b> <b><font color="#000000">Error</font></b><font color="#990000">(</font><font color="#FF0000">"Wrong value"</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">,</font> <font color="#FF6600">/value/</font> <font color="#990000">);</font> </tt> |
Apart from that there are at least 30 different testing frameworks to
use. I have chosen to use NodeUnit since I find that it handles
asynchronous testing well, and it has a nice UTF-8 output that looks
good in the terminal,
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<tt><i><font color="#9A1900">// ./test/test-doubled.js</font></i> <b><font color="#0000FF">var</font></b> doubled <font color="#990000">=</font> <b><font color="#000000">require</font></b><font color="#990000">(</font><font color="#FF0000">'../lib/doubled'</font><font color="#990000">);</font> <i><font color="#9A1900">// Exported functions are run by the test runner</font></i> exports<font color="#990000">[</font><font color="#FF0000">'calculate'</font><font color="#990000">]</font> <font color="#990000">=</font> <b><font color="#0000FF">function</font></b> <font color="#990000">(</font>test<font color="#990000">)</font> <font color="#FF0000">{</font> test<font color="#990000">.</font><b><font color="#000000">equal</font></b><font color="#990000">(</font>doubled<font color="#990000">.</font><b><font color="#000000">calculate</font></b><font color="#990000">(</font><font color="#993399">2</font><font color="#990000">),</font> <font color="#993399">4</font><font color="#990000">);</font> test<font color="#990000">.</font><b><font color="#000000">done</font></b><font color="#990000">();</font> <font color="#FF0000">}</font><font color="#990000">;</font> <i><font color="#9A1900">// An asynchronous test</font></i> exports<font color="#990000">[</font><font color="#FF0000">'read a number'</font><font color="#990000">]</font> <font color="#990000">=</font> <b><font color="#0000FF">function</font></b> <font color="#990000">(</font>test<font color="#990000">)</font> <font color="#FF0000">{</font> test<font color="#990000">.</font><b><font color="#000000">expect</font></b><font color="#990000">(</font><font color="#993399">1</font><font color="#990000">);</font> <i><font color="#9A1900">// Make sure the assertion is run</font></i> <b><font color="#0000FF">var</font></b> ev <font color="#990000">=</font> <b><font color="#0000FF">new</font></b> events<font color="#990000">.</font><b><font color="#000000">EventEmitter</font></b><font color="#990000">();</font> process<font color="#990000">.</font>openStdin <font color="#990000">=</font> <b><font color="#0000FF">function</font></b> <font color="#990000">()</font> <font color="#FF0000">{</font> <b><font color="#0000FF">return</font></b> ev<font color="#990000">;</font> <font color="#FF0000">}</font><font color="#990000">;</font> process<font color="#990000">.</font>exit <font color="#990000">=</font> test<font color="#990000">.</font>done<font color="#990000">;</font> console<font color="#990000">.</font>log <font color="#990000">=</font> <b><font color="#0000FF">function</font></b> <font color="#990000">(</font>str<font color="#990000">)</font> <font color="#FF0000">{</font> test<font color="#990000">.</font><b><font color="#000000">equal</font></b><font color="#990000">(</font>str<font color="#990000">,</font> <font color="#FF0000">'Doubled: 24'</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">;</font> doubled<font color="#990000">.</font><b><font color="#000000">read</font></b><font color="#990000">();</font> ev<font color="#990000">.</font><b><font color="#000000">emit</font></b><font color="#990000">(</font><font color="#FF0000">'data'</font><font color="#990000">,</font> <font color="#FF0000">'12'</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">;</font> </tt> |
There are already a lot of platforms providing Node as a service (PaaS
, Platform as a Service). Most of them are using
Heroku style deployment by pushing to a Git remote.
I’ll show three alternatives that all provide free Node hosting.
Joyent, the employers of Ryan Dahl, give you ssh access so that you
can install the modules you need. Deployment is done by pushing to
a Git remote.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<tt>$ ssh node@my-machine<font color="#990000">.</font>no<font color="#990000">.</font>de $ nmp install express $ git remote add node node@andersjanmyr<font color="#990000">.</font>no<font color="#990000">.</font>de<font color="#990000">:</font>repo $ git push node master Counting objects<font color="#990000">:</font> <font color="#993399">5</font><font color="#990000">,</font> <b><font color="#0000FF">done</font></b><font color="#990000">.</font> Delta compression using up to <font color="#993399">2</font> threads<font color="#990000">.</font> Compressing objects<font color="#990000">:</font> <font color="#993399">100</font><font color="#990000">%</font> <font color="#990000">(</font><font color="#993399">3</font><font color="#990000">/</font><font color="#993399">3</font><font color="#990000">),</font> <b><font color="#0000FF">done</font></b><font color="#990000">.</font> Writing objects<font color="#990000">:</font> <font color="#993399">100</font><font color="#990000">%</font> <font color="#990000">(</font><font color="#993399">3</font><font color="#990000">/</font><font color="#993399">3</font><font color="#990000">),</font> <font color="#993399">321</font> bytes<font color="#990000">,</font> <b><font color="#0000FF">done</font></b><font color="#990000">.</font> Total <font color="#993399">3</font> <font color="#990000">(</font>delta <font color="#993399">2</font><font color="#990000">),</font> reused <font color="#993399">0</font> <font color="#990000">(</font>delta <font color="#993399">0</font><font color="#990000">)</font> remote<font color="#990000">:</font> Starting node v0<font color="#990000">.</font><font color="#993399">4.7</font><font color="#990000">...</font> remote<font color="#990000">:</font> Successful To node@andersjanmyr<font color="#990000">.</font>no<font color="#990000">.</font>de<font color="#990000">:</font>repo 8f59169<font color="#990000">..</font>c1177b0 master -<font color="#990000">></font> master </tt> |
Nodester, gives you a command line tool, nodester, that you use to
install modules. Deployment by pushing to a Git remote.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<tt>$ nodester npm install express $ git push nodester master Counting objects<font color="#990000">:</font> <font color="#993399">5</font><font color="#990000">,</font> <b><font color="#0000FF">done</font></b><font color="#990000">.</font> Delta compression using up to <font color="#993399">2</font> threads<font color="#990000">.</font> Compressing objects<font color="#990000">:</font> <font color="#993399">100</font><font color="#990000">%</font> <font color="#990000">(</font><font color="#993399">3</font><font color="#990000">/</font><font color="#993399">3</font><font color="#990000">),</font> <b><font color="#0000FF">done</font></b><font color="#990000">.</font> Writing objects<font color="#990000">:</font> <font color="#993399">100</font><font color="#990000">%</font> <font color="#990000">(</font><font color="#993399">3</font><font color="#990000">/</font><font color="#993399">3</font><font color="#990000">),</font> <font color="#993399">341</font> bytes<font color="#990000">,</font> <b><font color="#0000FF">done</font></b><font color="#990000">.</font> Total <font color="#993399">3</font> <font color="#990000">(</font>delta <font color="#993399">2</font><font color="#990000">),</font> reused <font color="#993399">0</font> <font color="#990000">(</font>delta <font color="#993399">0</font><font color="#990000">)</font> remote<font color="#990000">:</font> Syncing repo with chroot remote<font color="#990000">:</font> From /node/hosted_apps/andersjanmyr<font color="#990000">/</font><font color="#993399">1346</font>-7856c14e6a5d92a6b5374ec4772a6da0<font color="#990000">.</font>git<font color="#990000">/.</font> remote<font color="#990000">:</font> 38f4e6e<font color="#990000">..</font>8f59169 master -<font color="#990000">></font> origin/master remote<font color="#990000">:</font> Updating 38f4e6e<font color="#990000">..</font>8f59169 remote<font color="#990000">:</font> Fast-forward remote<font color="#990000">:</font> Gemfile<font color="#990000">.</font>lock <font color="#990000">|</font> <font color="#993399">10</font> <font color="#990000">++++</font>------ remote<font color="#990000">:</font> <font color="#993399">1</font> files changed<font color="#990000">,</font> <font color="#993399">4</font> insertions<font color="#990000">(+),</font> <font color="#993399">6</font> deletions<font color="#990000">(</font>-<font color="#990000">)</font> remote<font color="#990000">:</font> Checking <font color="#990000">./.</font>git/hooks/post-receive remote<font color="#990000">:</font> Attempting to restart your app<font color="#990000">:</font> <font color="#993399">1346</font>-7856c14e6a5d92a6b5374ec4772a6da0 remote<font color="#990000">:</font> App restarted<font color="#990000">..</font> remote<font color="#990000">:</font> remote<font color="#990000">:</font> remote<font color="#990000">:</font> <font color="#990000"></font>m<font color="#990000">/</font> Nodester out <font color="#990000"></font>m<font color="#990000">/</font> remote<font color="#990000">:</font> remote<font color="#990000">:</font> To ec2-user@nodester<font color="#990000">.</font>com<font color="#990000">:</font>/node/hosted_apps/andersjanmyr<font color="#990000">/</font><font color="#993399">1346</font>-7856c14e6a5d92a6b5374ec4772a6da0<font color="#990000">.</font>git 38f4e6e<font color="#990000">..</font>8f59169 master -<font color="#990000">></font> master </tt> |
Cloud Foundry is one of the most interesting platforms in the cloud. It
was genius by VM Ware to open source the platform, allowing anyone to
set up their own cloud if they wish. If you don’t want to setup your own
Cloud Foundry Cloud, you can use the service hosted at
cloundfoundry.com.
With Cloud Foundry, you install the modules locally and then they are
automatically deployed as part of the vmc push. Push in this case does
not mean git push, but instead, copy all the files from my local machine
to the server.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<tt>$ npm install express <i><font color="#9A1900"># Install locally</font></i> mime@<font color="#993399">1.2</font><font color="#990000">.</font><font color="#993399">1</font> <font color="#990000">.</font>/node_modules/express/node_modules/mime connect@<font color="#993399">1.4</font><font color="#990000">.</font><font color="#993399">0</font> <font color="#990000">.</font>/node_modules/express/node_modules/connect qs@<font color="#993399">0.1</font><font color="#990000">.</font><font color="#993399">0</font> <font color="#990000">.</font>/node_modules/express/node_modules/qs express@<font color="#993399">2.3</font><font color="#990000">.</font><font color="#993399">0</font> <font color="#990000">.</font>/node_modules/express $ vmc push Would you like to deploy from the current directory<font color="#990000">?</font> <font color="#990000">[</font>Yn<font color="#990000">]:</font> Y Application Name<font color="#990000">:</font> snake Application Deployed URL<font color="#990000">:</font> <font color="#FF0000">'snake.cloudfoundry.com'</font><font color="#990000">?</font> Detected a Node<font color="#990000">.</font>js Application<font color="#990000">,</font> is this correct<font color="#990000">?</font> <font color="#990000">[</font>Yn<font color="#990000">]:</font> Memory Reservation <font color="#990000">[</font>Default<font color="#990000">:</font>64M<font color="#990000">]</font> <font color="#990000">(</font>64M<font color="#990000">,</font> 128M<font color="#990000">,</font> 256M<font color="#990000">,</font> 512M<font color="#990000">,</font> 1G or 2G<font color="#990000">)</font> Creating Application<font color="#990000">:</font> OK Would you like to <b><font color="#0000FF">bind</font></b> any services to <font color="#FF0000">'snake'</font><font color="#990000">?</font> <font color="#990000">[</font>yN<font color="#990000">]:</font> Uploading Application<font color="#990000">:</font> Checking <b><font color="#0000FF">for</font></b> available resources<font color="#990000">:</font> OK Packing application<font color="#990000">:</font> OK Uploading <font color="#990000">(</font>1K<font color="#990000">):</font> OK Push Status<font color="#990000">:</font> OK Staging Application<font color="#990000">:</font> OK Starting Application<font color="#990000">:</font> <font color="#990000">........</font>OK </tt> |
There are of course a bunch of tools that come with a new platform,
Jake, is a Javascript version of Rake, but I am happy with Rake and
I don’t see the need to switch. But, there are some tools that I cannot
live without when using Node.
If you use the vanilla node command then you have to restart it
every time you make a change to a file. That is awfully annoying and
there are already a number of solutions to the problem.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<tt><i><font color="#9A1900"># Nodemon watches the files in your directory and reloads them if necessary</font></i> $ npm install nodemon nodemon@<font color="#993399">0.3</font><font color="#990000">.</font><font color="#993399">2</font> <font color="#990000">..</font>/node_modules/nodemon $ nodemon server<font color="#990000">.</font>js <font color="#993399">30</font> Apr <font color="#993399">08</font><font color="#990000">:</font><font color="#993399">21</font><font color="#990000">:</font><font color="#993399">23</font> - <font color="#990000">[</font>nodemon<font color="#990000">]</font> running server<font color="#990000">.</font>js <font color="#990000">...</font> <i><font color="#9A1900"># Saving the file</font></i> <font color="#993399">30</font> Apr <font color="#993399">08</font><font color="#990000">:</font><font color="#993399">22</font><font color="#990000">:</font><font color="#993399">01</font> - <font color="#990000">[</font>nodemon<font color="#990000">]</font> restarting due to changes<font color="#990000">...</font> <i><font color="#9A1900"># Alternative</font></i> $ npm install supervisor $ supervisor server<font color="#990000">.</font>js DEBUG<font color="#990000">:</font> Watching directory <font color="#FF0000">'/evented-programming-with-nodejs/. </font> </tt> |
Another tool that it is hard to live without is a debugger. Node comes
with one built in. It has a gdb flavor to it and it is kind of rough.
|
1 2 3 4 5 6 7 8 9 10 11 |
<tt>$ node debug server<font color="#990000">.</font>js debug<font color="#990000">></font> run debugger listening on port <font color="#993399">5858</font> connecting<font color="#990000">...</font>ok <b><font color="#0000FF">break</font></b> <b><font color="#0000FF">in</font></b> <i><font color="#9A1900">#<Socket> ./server.js:9</font></i> debugger<font color="#990000">;</font> debug<font color="#990000">></font> p data<font color="#990000">.</font><b><font color="#000000">toString()</font></b><font color="#990000">;</font> tapir </tt> |
|
1 2 3 4 5 6 7 8 |
<tt><i><font color="#9A1900">// Javascript</font></i> <b><font color="#0000FF">var</font></b> echo <font color="#990000">=</font> net<font color="#990000">.</font><b><font color="#000000">createServer</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">(</font>socket<font color="#990000">)</font> <font color="#FF0000">{</font> socket<font color="#990000">.</font><b><font color="#000000">on</font></b><font color="#990000">(</font><font color="#FF0000">'data'</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>data<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">debugger</font></b><font color="#990000">;</font> <i><font color="#9A1900">// <= break into debugger</font></i> socket<font color="#990000">.</font><b><font color="#000000">write</font></b><font color="#990000">(</font>data<font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> </tt> |
If you want a GUI debugger, it is possible to use the one that comes with
Chrome by installing the node-inspector. It is started similarly to
the built in debugger, but the --debug is an option instead of
a subcommand.
|
1 2 3 4 5 |
<tt>$ node-inspector <font color="#990000">&</font> visit http<font color="#990000">://</font><font color="#993399">0.0</font><font color="#990000">.</font><font color="#993399">0.0</font><font color="#990000">:</font><font color="#993399">8080</font>/debug<font color="#990000">?</font><font color="#009900">port</font><font color="#990000">=</font><font color="#993399">5858</font> to start debugging $ node --debug server<font color="#990000">.</font>js debugger listening on port <font color="#993399">5858</font> </tt> |
After that you can just fire up Chrome on the URL,
http://0.0.0.0:8080/debug?port=5858 and you can debug the node process
just as if it was running in the browser.
Idioms, patterns, techniques, call it what you like. Javascript code is
littered with callbacks, and event more so with Node. Here are some tips
on how to write good asynchronous code with Node.
It is easy to forget to escape from the function after a callback has
been called. An easy way to remedy this problem is to call return before
every call to a callback. Even though the value is never used by the
caller, it is an easy pattern to recognize and it prevents bugs.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
<tt> <b><font color="#0000FF">function</font></b> <b><font color="#000000">doSomething</font></b><font color="#990000">(</font>response<font color="#990000">,</font> callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#000000">doAsyncCall</font></b><font color="#990000">(</font><font color="#FF0000">'tapir'</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>err<font color="#990000">,</font> result<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">if</font></b> <font color="#990000">(</font>err<font color="#990000">)</font> <font color="#FF0000">{</font> <i><font color="#9A1900">// return on the callback</font></i> <b><font color="#0000FF">return</font></b> <b><font color="#000000">callback</font></b><font color="#990000">(</font>err<font color="#990000">);</font> <font color="#FF0000">}</font> <i><font color="#9A1900">// return on the callback</font></i> <b><font color="#0000FF">return</font></b> <b><font color="#000000">callback</font></b><font color="#990000">(</font><b><font color="#0000FF">null</font></b><font color="#990000">,</font> result<font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> <font color="#FF0000">}</font> </tt> |
Exceptions that occur in callbacks cannot be handled the way we are used
to, since the context is different. The solution to this is to pass
along the exception as a parameter to the callback. In Node the
convetion is to pass the error as the first parameter into the callback.
|
1 2 3 4 5 6 7 8 |
<tt><b><font color="#0000FF">function</font></b> <b><font color="#000000">insertIntoTable</font></b><font color="#990000">(</font>row<font color="#990000">,</font> <b><font color="#000000">function</font></b><font color="#990000">(</font>err<font color="#990000">,</font> data<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">if</font></b> <font color="#990000">(</font>err<font color="#990000">)</font> <b><font color="#0000FF">return</font></b> <b><font color="#000000">callback</font></b><font color="#990000">(</font>err<font color="#990000">);</font> <font color="#990000">...</font> <i><font color="#9A1900">// Everything is OK</font></i> <b><font color="#0000FF">return</font></b> <b><font color="#000000">callback</font></b><font color="#990000">(</font><b><font color="#0000FF">null</font></b><font color="#990000">,</font> <font color="#FF0000">'row inserted'</font><font color="#990000">);</font> <font color="#FF0000">}</font> </tt> |
If you have multiple tasks that need to be finished before you take some
new action, this can be handled with a simple counter. Here is an
example of a simple function that starts up a bunch of functions in
parallel and waits for all of them to finish before calling the
callback.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<tt><i><font color="#9A1900">// Do all in parallel</font></i> <b><font color="#0000FF">function</font></b> <b><font color="#000000">doAll</font></b><font color="#990000">(</font>collection<font color="#990000">,</font> callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">var</font></b> left <font color="#990000">=</font> collection<font color="#990000">.</font>length<font color="#990000">;</font> collection<font color="#990000">.</font><b><font color="#000000">forEach</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">(</font>fun<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#000000">fun</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font> <b><font color="#0000FF">if</font></b> <font color="#990000">(--</font>left <font color="#990000">==</font> <font color="#993399">0</font><font color="#990000">)</font> <b><font color="#000000">callback</font></b><font color="#990000">();</font> <font color="#FF0000">}</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">;</font> <i><font color="#9A1900">// Use it</font></i> <b><font color="#0000FF">var</font></b> result <font color="#990000">=</font> <font color="#990000">[];</font> <b><font color="#000000">doAll</font></b><font color="#990000">([</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#000000">setTimeout</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font>result<font color="#990000">.</font><b><font color="#000000">push</font></b><font color="#990000">(</font><font color="#993399">1</font><font color="#990000">);</font> <b><font color="#000000">callback</font></b><font color="#990000">();</font><font color="#FF0000">}</font><font color="#990000">,</font> <font color="#993399">2000</font> <font color="#990000">)</font><font color="#FF0000">}</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#000000">setTimeout</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font>result<font color="#990000">.</font><b><font color="#000000">push</font></b><font color="#990000">(</font><font color="#993399">2</font><font color="#990000">);</font> <b><font color="#000000">callback</font></b><font color="#990000">();</font><font color="#FF0000">}</font><font color="#990000">,</font> <font color="#993399">3000</font> <font color="#990000">)</font><font color="#FF0000">}</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#000000">setTimeout</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font>result<font color="#990000">.</font><b><font color="#000000">push</font></b><font color="#990000">(</font><font color="#993399">3</font><font color="#990000">);</font> <b><font color="#000000">callback</font></b><font color="#990000">();</font><font color="#FF0000">}</font><font color="#990000">,</font> <font color="#993399">1000</font> <font color="#990000">)</font><font color="#FF0000">}</font> <font color="#990000">],</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font> <b><font color="#0000FF">return</font></b> result<font color="#990000">;</font> <font color="#FF0000">}</font> <i><font color="#9A1900">// returns [3, 1, 2]</font></i> </tt> |
Sometimes the ordering is important. Here is a simple function that
makes sure that the calls are executed in sequence. It uses recursion to
to make sure that the calls are handled in the correct order. It also
uses the Node function process.nextTick() to prevent the stack from
getting to large for large collections. Similar results can be obtained
with setTimeout() in browser Javascript. It can be seen as a simple
trick to achieve tail recursion.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<tt><b><font color="#0000FF">function</font></b> <b><font color="#000000">doInSequence</font></b><font color="#990000">(</font>collection<font color="#990000">,</font> callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">var</font></b> queue <font color="#990000">=</font> collection<font color="#990000">.</font><b><font color="#000000">slice</font></b><font color="#990000">(</font><font color="#993399">0</font><font color="#990000">);</font> <i><font color="#9A1900">// Duplicate</font></i> <b><font color="#0000FF">function</font></b> <b><font color="#000000">iterate</font></b><font color="#990000">()</font> <font color="#FF0000">{</font> <b><font color="#0000FF">if</font></b> <font color="#990000">(</font>queue<font color="#990000">.</font>length <font color="#990000">===</font> <font color="#993399">0</font><font color="#990000">)</font> <b><font color="#0000FF">return</font></b> <b><font color="#000000">callback</font></b><font color="#990000">();</font> <i><font color="#9A1900">// Take the first element</font></i> <b><font color="#0000FF">var</font></b> fun <font color="#990000">=</font> queue<font color="#990000">.</font><b><font color="#000000">splice</font></b><font color="#990000">(</font><font color="#993399">0</font><font color="#990000">,</font> <font color="#993399">1</font><font color="#990000">)[</font><font color="#993399">0</font><font color="#990000">];</font> <b><font color="#000000">fun</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">(</font>err<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">if</font></b> <font color="#990000">(</font>err<font color="#990000">)</font> <b><font color="#0000FF">throw</font></b> err<font color="#990000">;</font> <i><font color="#9A1900">// Call it without building up the stack</font></i> process<font color="#990000">.</font><b><font color="#000000">nextTick</font></b><font color="#990000">(</font><b><font color="#000000">iterate</font></b><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">);</font> <font color="#FF0000">}</font> <b><font color="#000000">iterate</font></b><font color="#990000">();</font> <font color="#FF0000">}</font> <b><font color="#0000FF">var</font></b> result <font color="#990000">=</font> <font color="#990000">[];</font> <b><font color="#000000">doInSequence</font></b><font color="#990000">([</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#000000">setTimeout</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font>result<font color="#990000">.</font><b><font color="#000000">push</font></b><font color="#990000">(</font><font color="#993399">1</font><font color="#990000">);</font> <b><font color="#000000">callback</font></b><font color="#990000">();</font><font color="#FF0000">}</font><font color="#990000">,</font> <font color="#993399">2000</font> <font color="#990000">)</font><font color="#FF0000">}</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#000000">setTimeout</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font>result<font color="#990000">.</font><b><font color="#000000">push</font></b><font color="#990000">(</font><font color="#993399">2</font><font color="#990000">);</font> <b><font color="#000000">callback</font></b><font color="#990000">();</font><font color="#FF0000">}</font><font color="#990000">,</font> <font color="#993399">3000</font> <font color="#990000">)</font><font color="#FF0000">}</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>callback<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#000000">setTimeout</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font>result<font color="#990000">.</font><b><font color="#000000">push</font></b><font color="#990000">(</font><font color="#993399">3</font><font color="#990000">);</font> <b><font color="#000000">callback</font></b><font color="#990000">();</font><font color="#FF0000">}</font><font color="#990000">,</font> <font color="#993399">1000</font> <font color="#990000">)</font><font color="#FF0000">}</font> <font color="#990000">],</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font> <b><font color="#0000FF">return</font></b> result<font color="#990000">;</font> <font color="#FF0000">}</font><font color="#990000">);</font> <i><font color="#9A1900">// Returns [1, 2, 3]</font></i> </tt> |
If you don’t want to write these functions yourself, there are a few
libraries that can help you out. I’ll show two version that I like.
Fibers are also called co-routines. Fibers provide two functions,
suspend and resume, which allows us to write code in a synchronous
looking style. In the Node version of fibers,
node-fibers, suspend and
resume are called yield() and run() instead.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<tt><b><font color="#000000">require</font></b><font color="#990000">(</font><font color="#FF0000">'fibers'</font><font color="#990000">);</font> <b><font color="#0000FF">var</font></b> print <font color="#990000">=</font> <b><font color="#000000">require</font></b><font color="#990000">(</font><font color="#FF0000">'util'</font><font color="#990000">).</font>print<font color="#990000">;</font> <b><font color="#0000FF">function</font></b> <b><font color="#000000">sleep</font></b><font color="#990000">(</font>ms<font color="#990000">)</font> <font color="#FF0000">{</font> <b><font color="#0000FF">var</font></b> fiber <font color="#990000">=</font> Fiber<font color="#990000">.</font>current<font color="#990000">;</font> <b><font color="#000000">setTimeout</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font> fiber<font color="#990000">.</font><b><font color="#000000">run</font></b><font color="#990000">();</font> <font color="#FF0000">}</font><font color="#990000">,</font> ms<font color="#990000">);</font> <b><font color="#000000">yield</font></b><font color="#990000">();</font> <font color="#FF0000">}</font> <b><font color="#000000">Fiber</font></b><font color="#990000">(</font><b><font color="#0000FF">function</font></b><font color="#990000">()</font> <font color="#FF0000">{</font> <b><font color="#000000">print</font></b><font color="#990000">(</font><font color="#FF0000">'wait... '</font> <font color="#990000">+</font> <b><font color="#0000FF">new</font></b> Date <font color="#990000">+</font> <font color="#FF0000">'</font><font color="#CC33CC">n</font><font color="#FF0000">'</font><font color="#990000">);</font> <b><font color="#000000">sleep</font></b><font color="#990000">(</font><font color="#993399">1000</font><font color="#990000">);</font> <b><font color="#000000">print</font></b><font color="#990000">(</font><font color="#FF0000">'ok... '</font> <font color="#990000">+</font> <b><font color="#0000FF">new</font></b> Date <font color="#990000">+</font> <font color="#FF0000">'</font><font color="#CC33CC">n</font><font color="#FF0000">'</font><font color="#990000">);</font> <font color="#FF0000">}</font><font color="#990000">).</font><b><font color="#000000">run</font></b><font color="#990000">();</font> <b><font color="#000000">print</font></b><font color="#990000">(</font><font color="#FF0000">'back in main</font><font color="#CC33CC">n</font><font color="#FF0000">'</font><font color="#990000">);</font> </tt> |
Fibers are a very nice way of writing asynchronous code but, in Node,
they have one drawback. They are not supported without patching the V8
virtual machine. The patching is done when you install node-fibers and
you have to run the command node-fibers instead of node to use it.
async LibraryIf you don’t want to use the patched version of V8, I can recommend the
async library. Async provides
around 20 functions that include the usual ‘functional’ suspects (map,
reduce, filter, forEach…) as well as some common patterns for
asynchronous flow control (parallel, series, waterfall…). All these
functions assume you follow the Node convention of providing a single
callback as the last argument of your async function.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<tt>async<font color="#990000">.</font><b><font color="#000000">map</font></b><font color="#990000">([</font><font color="#FF0000">'file1'</font><font color="#990000">,</font><font color="#FF0000">'file2'</font><font color="#990000">,</font><font color="#FF0000">'file3'</font><font color="#990000">],</font> fs<font color="#990000">.</font>stat<font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>err<font color="#990000">,</font> results<font color="#990000">)</font><font color="#FF0000">{</font> <i><font color="#9A1900">// results is now an array of stats for each file</font></i> <font color="#FF0000">}</font><font color="#990000">);</font> async<font color="#990000">.</font><b><font color="#000000">filter</font></b><font color="#990000">([</font><font color="#FF0000">'file1'</font><font color="#990000">,</font><font color="#FF0000">'file2'</font><font color="#990000">,</font><font color="#FF0000">'file3'</font><font color="#990000">],</font> path<font color="#990000">.</font>exists<font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">(</font>results<font color="#990000">)</font><font color="#FF0000">{</font> <i><font color="#9A1900">// results now equals an array of the existing files</font></i> <font color="#FF0000">}</font><font color="#990000">);</font> async<font color="#990000">.</font><b><font color="#000000">parallel</font></b><font color="#990000">([</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font><font color="#FF0000">{</font> <font color="#990000">...</font> <font color="#FF0000">}</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font><font color="#FF0000">{</font> <font color="#990000">...</font> <font color="#FF0000">}</font> <font color="#990000">],</font> callback<font color="#990000">);</font> async<font color="#990000">.</font><b><font color="#000000">series</font></b><font color="#990000">([</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font><font color="#FF0000">{</font> <font color="#990000">...</font> <font color="#FF0000">}</font><font color="#990000">,</font> <b><font color="#0000FF">function</font></b><font color="#990000">()</font><font color="#FF0000">{</font> <font color="#990000">...</font> <font color="#FF0000">}</font> <font color="#990000">],</font> callback<font color="#990000">);</font> </tt> |
Node is definitely an interesting platform. The possibility to have
Javascript running through the whole stack, from the browser all the way
down into the database (if you use something like CouchDB or MongoDB)
really appeals to me. The easy way to deploy code to multiple, different
cloud providers is also a good argument for Node.
@Gunnar, I hear you :)
Nice article, and anything that mentions tapirs is a win in my book.
@Roger, Deft looks interesting, especially the performance graphs!
@Magnus, I agree, whiskey looks good. Thanks for the tip.
As already mentioned, nice article! Wanted to add that while developing my experimental ‘template’ like system WebGenJS (yes, another shameless plug; https://github.com/ernstsson/WebGenJS) I’ve been using whiskey (https://github.com/cloudkick/whiskey) for unit testing. It has a very nice node-jscoverage integration for code coverage reports. Very useful!
Interesting article about node.js. (You might want to add Deft to the History section, in conjunction with Goliath e.g. Deft: https://github.com/rschildmeijer/deft) disclaimer: Im a Deft committer