I've been programming in JS since the previous millennium (compilers, parser generators, 3-D engines, browser extensions, web servers, Comet in 2000) and I've used Node on and off for a few years now. V8 is pretty awesome, but outside of a relatively narrow niche, the advantage of Node doesn't seem that huge to me.
* Yes, your code runs a lot faster in V8 than in CPython or Ruby, maybe a factor of 3 to 10 slower than C (http://benchmarksgame.alioth.debian.org/u32/benchmark.php?te...) instead of the factor of 30 you get with CPython or YARV (http://benchmarksgame.alioth.debian.org/u32/benchmark.php?te...) or the factor of 100 you get with MRI Ruby. But much of the time, if a factor of 30 is a problem, so is a factor of 10! And there are plenty of language implementations that get closer to C than V8 does, without being as error-prone and verbose as C (Java, SBCL, Ada (just kidding), Haskell, OCaml, Scala, occasionally LuaJIT). PyPy has similar performance overall to V8, but a different performance profile. See http://speed.pypy.org/ for details.
* JS is a pretty reasonable language, and CS is even better, despite its lack of getters and setters, its stupid Ruby-derived inclusive-bounds ranges, and a few other minor warts. But it's not nearly as clean as Python or as flexible as Ruby.
* Node makes you rewrite your program into explicit continuation-passing style every time you do I/O, in order to maintain responsiveness. Also, every time you do a potentially long computation, unless they've finally gotten around to adding Web Workers to Node. I've done this in order to get massively scalable I/O in high-performance systems in C, Python, and JS, and it is my considered opinion that it is sometimes not the best way to do things. In cases where this is the best option, Python has Twisted and Tornado, which give you the massively-scalable nonblocking goodness while they still let you run other threads if that's what you think best.
* npm is a pretty amazing ecosystem, but the Python, Ruby, and C ecosystems are orders of magnitude bigger. On my netbook right now, among other things, I have Python bindings to 0MQ, D-Bus, GConf, TidyLib, DNS, GObject, CUPS, Cairo, and the GNOME keyring. Of these, 0MQ, D-Bus, DNS, and Cairo have bindings in npm, while GConf, TidyLib, GObject, CUPS, and the GNOME keyring do not. In realms like natural language processing, symbolic mathematics, and numerical computation (e.g. DSP), there's nothing in the JS world that comes close. Note that this objection applies also to PyPy, since many Python bindings do not yet work with PyPy.
PyPy also offers massive multithreading (a la Erlang, Golang, or rust) and sandboxing (the ability to run untrusted code safely, at least in theory); it contains a generalized JIT compiler generator that allows you to write JIT compilers for other languages very easily; and the PyPy people are working on software transactional memory and dynamic code generation for numerical algorithms.
In summary, I agree that Node is pretty awesome, especially, as you say, coupled with CoffeeScript, and also when you want to share code between browser and server. But there are still valid reasons for choosing other alternatives.
I don't see Python as being cleaner than CoffeeScript. CS is very similar but with less punctuation. How do you figure that one?
Have you tried using CoffeeScript indented with two spaces, or using the async module? You don't always have to do continuation passing, and I feel like Node.js's way is a lot more straightforward than anything like Twisted.
> I don't see Python as being cleaner than CoffeeScript. CS is very similar but with less punctuation. How do you figure that one?
It's more semantics than syntax, although CS's syntax is sufficiently complex and nonredundant that the compiler sometimes reports syntax errors in confusing places, or worse, finds a way to interpret them as something I didn't want them to mean. But syntax can suck my dick. It's nothing more than a constant factor. It's more things like:
* No iteration protocol.
* The built-in dictionary type only allows string keys.
* The built-in dictionary type has magical keys like "constructor" by default.
* [0..4] includes 4. The correct thing, [0...4], has a longer spelling.
* [0...i] has i items, except when i is negative, in which case it has -i items. (To be fair, Python has a similarly screwed-up special case in its array indexing.)
* No built-in lexicographical comparison of arbitrary sequences.
* No comparison protocol.
* String conversion of aggregates is brain-dead. '' + [0...4] == '' + [[0...4]].
* It inherits JS's incorrect closure of this; { x: (=> (=> @top)), top: 5 }.x()() isn't 5.
> using the async module? You don't always have to do continuation passing
I haven't tried using the async module, but you got my hopes up. No dice, though. All of its functions take a continuation as their last argument!
There's a lot to be said for straightforwardness, but Twisted's non-straightforwardness justifies itself by nuking boilerplate.
* Yes, your code runs a lot faster in V8 than in CPython or Ruby, maybe a factor of 3 to 10 slower than C (http://benchmarksgame.alioth.debian.org/u32/benchmark.php?te...) instead of the factor of 30 you get with CPython or YARV (http://benchmarksgame.alioth.debian.org/u32/benchmark.php?te...) or the factor of 100 you get with MRI Ruby. But much of the time, if a factor of 30 is a problem, so is a factor of 10! And there are plenty of language implementations that get closer to C than V8 does, without being as error-prone and verbose as C (Java, SBCL, Ada (just kidding), Haskell, OCaml, Scala, occasionally LuaJIT). PyPy has similar performance overall to V8, but a different performance profile. See http://speed.pypy.org/ for details.
* JS is a pretty reasonable language, and CS is even better, despite its lack of getters and setters, its stupid Ruby-derived inclusive-bounds ranges, and a few other minor warts. But it's not nearly as clean as Python or as flexible as Ruby.
* Node makes you rewrite your program into explicit continuation-passing style every time you do I/O, in order to maintain responsiveness. Also, every time you do a potentially long computation, unless they've finally gotten around to adding Web Workers to Node. I've done this in order to get massively scalable I/O in high-performance systems in C, Python, and JS, and it is my considered opinion that it is sometimes not the best way to do things. In cases where this is the best option, Python has Twisted and Tornado, which give you the massively-scalable nonblocking goodness while they still let you run other threads if that's what you think best.
* npm is a pretty amazing ecosystem, but the Python, Ruby, and C ecosystems are orders of magnitude bigger. On my netbook right now, among other things, I have Python bindings to 0MQ, D-Bus, GConf, TidyLib, DNS, GObject, CUPS, Cairo, and the GNOME keyring. Of these, 0MQ, D-Bus, DNS, and Cairo have bindings in npm, while GConf, TidyLib, GObject, CUPS, and the GNOME keyring do not. In realms like natural language processing, symbolic mathematics, and numerical computation (e.g. DSP), there's nothing in the JS world that comes close. Note that this objection applies also to PyPy, since many Python bindings do not yet work with PyPy.
PyPy also offers massive multithreading (a la Erlang, Golang, or rust) and sandboxing (the ability to run untrusted code safely, at least in theory); it contains a generalized JIT compiler generator that allows you to write JIT compilers for other languages very easily; and the PyPy people are working on software transactional memory and dynamic code generation for numerical algorithms.
In summary, I agree that Node is pretty awesome, especially, as you say, coupled with CoffeeScript, and also when you want to share code between browser and server. But there are still valid reasons for choosing other alternatives.