The secrets of Node’s success

Why Node.js has caught on while other server-side JavaScript implementations faltered.

In the short time since its initial release in late 2009, Node.js has captured the interest of thousands of experienced developers, grown a package manager and a corpus of interesting modules and applications, and even spawned a number of startups.

What is it about this technology that makes it interesting to developers? And why has it succeeded while other server-side JavaScript implementations linger in obscurity or fail altogether?

The key factors are performance, timing, and focusing on a real problem that wasn’t easily solved with other server-side dynamic languages.

Browser wars and JavaScript performance

In the early 2000s, AJAX web development was coming into its own and placing increasing demands on browsers’ JavaScript engines. New JavaScript libraries such as YUI, Dojo and jQuery were allowing developers to do much more with web user interface (UI), creating a user experience for web applications that mimicked the behavior of desktop applications.

As JavaScript libraries and websites became more complex and users started to notice poor performance in their browsers, browser developers started to focus seriously on their JavaScript engines.

The race for faster JavaScript engines heated up in September 2008 when Google released Chrome and the Chromium source code. The engine behind it was V8 and it outperformed all others. This helped spur the developers of Firefox, Safari, Opera and Internet Explorer to improve JavaScript performance in their browsers and it opened a new front in the browser wars.

Technically speaking, V8 takes a slightly novel approach to improving performance. Certain JavaScript objects are dynamically compiled directly into native machine code before execution based on a predictive analysis of the code.

This, along with a new approach to property access and a more efficient garbage collection system enabled Chrome to initially post significantly faster benchmarks than other browsers.

The other browsers responded with improved or completely rewritten JavaScript engines that matched or exceeded V8’s benchmarks. These optimizations are still going on, and Google’s V8 is benefiting from the healthy, often technically brilliant, competition. Compared to the interpreters for server-side dynamic languages like Ruby, Python, PHP and Perl, JavaScript now has several efficient and incredibly fast runtimes.

Ryan Dahl, creator of Node.js, chose the V8 engine for Node. This has an additional benefit for a server-side implementation.

The predictive optimization of JavaScript works fairly well in the Chrome browser, but it is much more effective for server applications where the same chunks of code tend to be run multiple times. V8 is able to refine its optimizations and soon ends up with very efficient cached machine code.

Node has an additional performance advantage (a big one) that is not directly tied to V8, but we’ll get to that in a bit.

The rehabilitation of JavaScript

JavaScript was once widely regarded as an awful hack of a language. Many programmers still feel this way, but the prejudice is starting to fade, mostly because there is a growing body of good code that shows off the language.

One person who has done much to pinpoint JavaScript’s technical weak points is Douglas Crockford. Fortunately, instead of stopping there, he has also created JSLint and written “JavaScript: The Good Parts” to help developers write better code while avoiding most of the “bad parts” of the language. In his presentations and posts, one of his core assertions is that:

… despite JavaScript’s astonishing shortcomings, deep down, in its
core, it got something very right. When you peel away the cruft, there
is an expressive and powerful programming language there. That
language is being used well in many Ajax libraries to manage and
augment the DOM, producing an application platform for interactive
applications delivered as web pages. Ajax has become popular because
JavaScript works. It works surprisingly well.

Without getting into the details of which parts are good or bad, we have seen in the past few years that professional developers have come to realize that JavaScript is not going away. Many of developers have gotten on with the task of building complex, well-designed applications and libraries. There are still problems with JavaScript and with its specification, but programmers are now much less likely to dismiss it out of hand.

Previous server-side JavaScript frameworks had a much harder time overcoming the negative mindset about the language. By the time Node arrived, JavaScript had overcome the most of its image problem.

Node.js solves a real problem

Wikipedia has a fairly comprehensive “Comparison of server-side JavaScript solutions“. Node is in there, but most of the others listed are not nearly so well known. The use of the term “solutions” is interesting, as most of these projects are solutions to problems that have already been solved by other languages.

Python, Java, Ruby, PHP, Perl and others are all still extremely good choices for most types of dynamic web applications. They talk to databases, crunch numbers, validate data, and parse templates. They are high-level languages, and there are several MVC frameworks for each of them for quick web app creation. Node is sometimes touted as the next Ruby-on-Rails, but this a bad comparison and misses the point of what Node is for.

Node is not trying to solve the same problems as Rails, and it’s not competing head-on with any of the other languages or frameworks in the areas where they do well. It was made for, and is most successful at, solving a special set of problems with modern web applications. What can it do that these other languages cannot?

It turns out that what JavaScript can do is the flip side of something it can’t do: blocking I/O.

Evented I/O

JavaScript itself can’t actually read or write to the filesystem. This ability was omitted from the language because it wasn’t necessary for its job in the browser, so Node was able to start from scratch with an I/O system based on event loops.

Node is all about “evented I/O,” but what does that actually mean?

To those of us who are either not programmers or are not familiar with event loops, an analogy might help.

You’re in a grocery store with a list of items to buy. You wheel your cart around the store, pick up one item at a time, put it in your cart, then take the cart through the checkout. You can optimize this slightly by fetching the items in a sane order, but you can’t go get the milk while you’re waiting at the deli counter.

If you’re in a hurry, you might start thinking of crazy ways to speed up the process. You could enlist a number of other shoppers with shopping carts and send each out to buy a single item. This would create bottlenecks in narrow isles and a huge traffic jam at the checkout

This is clearly an insane way to solve the issue because it throws more shopping carts and cash registers at the problem than needed.

Programming languages that block on I/O often try to solve similar problems by spawning additional threads or processes (c.f. Apache, sendmail). This can be expensive in terms of memory usage, and an analysis of Python’s Global Interpreter Lock shows just how expensive the traffic jam can be in terms of CPU utilization.

JavaScript and Node use event loops and callbacks to approach the problem differently.

Returning to the shopping example: If you had a group of kids along with you on your shopping trip, you could send each off to get a single item and return them to the cart. When they’ve all returned, you can proceed through the checkout. The time taken in fetching items would be the maximum time for retrieving a single item (the kid who had to wait at the deli counter), rather than the sum (picking up the items in sequence). Using runners for the small, simple task of fetching items is a more efficient way of parallelizing the problem than sending out full-fledged shoppers and carts.

It’s not a perfect analogy by any means, but more succinct and accurate descriptions involve code or pseudo-code. Ryan Dahl’s initial presentation at JSConf 2009 used the following example:

Here the database query blocks the program from doing anything else until the query is returned, whereas in an event loop:

… the program can continue doing things while waiting for the function to call provide its callback.

Node provides non-blocking libraries for database, file and network access. Since I/O is not a fundamental part of JavaScript, nothing had to be taken away to add them. Python’s Twisted and Ruby’s Event Machine have to work around some basic language components in order to get similar evented behavior.

So, in addition to the performance wins Node gets “for free” by using the V8 JavaScript engine, the event loop model itself allows Node servers to handle massive concurrencies in network connections very efficiently. It often approaches the benchmarks achieved by high-performance reverse proxies like Nginx (which is also based on an event loop).

Sharing code between the browser and server

Using the same language on the server that you’re already using in the browser has been the promise of many server-side JavaScript (SSJS) systems. The idea of “one language to rule them all” is appealing to developers who have been bounced from one language to another as each new technology emerges.

Aptana Jaxer, one of the better known recent SSJS implementations, hoped to engage AJAX developers with this model. In principle, it’s a good idea. You can use the same libraries to validate data on both sides, call server-side JavaScript functions directly from the browser and pre-construct HTML DOM on the server with browser UI libraries to speed up the initial page load.

Jaxer did not see anywhere near the uptake that Node has, and this could be partly because of timing. To many, Jaxer looked like a reimplementation of ASP. It also didn’t have Node’s performance benchmarks, and it didn’t focus on the issue of blocking I/O. Despite its interesting possibilities, Jaxter didn’t reach the tipping point of forming a vibrant community.

Critical mass for Node.js

Most new technologies die not because of their lack of merit, but because of obscurity. A new language or framework needs a large enough pool of users and core developers in order for it to be sustainable. Large marketing campaigns and the backing of a big company can push a programming language or technology framework into the mainstream, but sometimes it happens from the ground up.

Node generated excitement on its first release because programmers find it interesting and powerful. It’s hard to find negative comments from those who are using it.

Because of the instant appeal, there were enough early adopters to start a vibrant community and a large number projects, many of which are open source. These applications, 96 and counting linked from the Node wiki, show off many of the amazing things Node can do. They provide developers with example code and inspiration.

The wiki also lists 86 companies and startups using Node. Though it’s not an exhaustive list, and many of the companies listed are quite small, there are at least two significant players.

Joyent is the corporate home of Node. It employs Ryan Dahl (Node’s creator), Isaac Schlueter (creator of NPM), and other Node contributors. Joyent owns the Node trademark and copyright, and the company recently launched No.de, a hosting service for Node applications. This gives Node a stable, funded base of development resources and a spokesperson for the project in the corporate world.

The other big player is HP. Shortly after HP acquired Palm, Palm’s webOS mobile operating system added Node. This was a smart move for HP, and was very well received by the webOS
community:

If you think about it, Node delivers a services platform for the
cloud, so is there a way that we could work together? We got together
with Ryan Dahl of Node to try this out, and it turns out that Node
works fantastically well on a mobile device! Major kudos should go to
the V8 team for creating a great VM and to Ryan for writing efficient
code that scaled down from the cloud to the device. — Dion Almaer

Putting Node on a mobile device turns the idea of Server Side JavaScript on its head, but why not? With Node the JavaScript engine is small enough, the code is portable enough, and the programming model is light and asynchronous – a perfect combination a mobile device. It’s possible that this, rather than a Rails-like MVC framework or a content management system, will be what propels Node into ubiquity.

Node is not the “next” anything

Node is something new, and that’s why programmers are interested in it.

Node has changed our mental image of what a server can be. It doesn’t have to be running on a high-performance blade in an air-conditioned co-lo serving millions of requests and gigabytes of data. It can be in your pocket synchronizing your contacts whenever it finds Wi-Fi. It can be caching a web application for faster, local access. It can be a peer-to-peer web server. And it can be a number of things we haven’t even thought of yet.

tags: , , ,

Get the O’Reilly Web Platform Newsletter

Stay informed. Receive weekly insight from industry insiders—plus exclusive content and offers.

Comments are closed.