We all have different performance requirements, but in my experience, when you actually care about the performance of CPU intensive task, child_process.fork or WebWorkers are still insufficient.
Instead, sometimes you use node native modules, sometimes you separate you child_process.spawn something written in Go, C++, or Rust(,etc), and sometimes you set up a separate work "queue" to pass work either on the same machine or over the network. I've used both kafka, zeromq, or even just files on the s3. A linux domain socket is nice too.
The performance of the CPU bound task and performing any CPU bound task on the main IO thread are 2 different things. The article was about the problem you face when you do CPU bound task on the main IO thread.
The WebWorkers and other approaches are about how to avoid using the IO thread to do CPU tasks. How the performance of those CPU tasks is depends on other factors. You can use WebAssembly or asm.js code to reach the performance of natively compiled code.
I don't necessarily buy being blocked by CPU-intensive operations as a rationale as to why you shouldn't Node, given that it's pretty trivial to offload these onto a separate process.
It is non trivial to share state between node threads. The state is shuffled around outside of the VM unlike go, Java, and c#. In those languages, the overhead of sharing a variable are basically zero.
In node you get sharing at basically the speed of TCP local sockets on the machine. So maybe 5GBps. With natively threaded languages you get sharing at the speed of the cpu cache, orders of magnitude faster
If performance is important enough that multithreading comes into play, don't use node.
They don't share variables low level, so the problem remains. In Java and similar languages the variables are shared at the machine level, including atomics
They don't share variables low level, so the problem remains. In Java and similar languages the variables are shared at the machine level, including atomics
I use NodeJS like AWS lambda functions but running on my own tiny VPS (Digital Ocean droplets). Why instead of lambda? B/c I have zero restrictions on NPM packages and many other things I can use. Now, I do not write full APIs, instead I use everything a BAAS has to offer (like Firebase) and complement what it lacks. For example:
- When a Firebase ref changes I listen to the event in Nodejs and update a full text search index elsewhere.
- When a Firebase ref is created I send the appropriate transactional email/push/sms.
- Do data validations before pushing to Firebase.
So in general, I do things that cannot/should not be done on the client-side while still opting for serverless architectures.
PS: Parse.com was great in that it had server-side code that was run on events like object updated/created. The code was NodeJS. In sum, it had lambda-like functionality already built-in. But Parse.com closed shop. Not sure if any of its spin-offs are offering a good service at decent prices.
a) So you reimplemented all of the goodness of twisted in javascript? :)
b) and you have to debug that new pile of code?
c) with a language (in it's original form) that has a bunch of issues, despite being fun to develop in
Maybe Node with an ES6 backend? Maybe that's better. However, from my perspective, event based development works for some apps but is a total PITA for traditional workloads (websites).
I would think about Node for a messaging use case, or message processing.
While it's true that node can handle CPU intense tasks with WebWorkers or some other clustering there are also memory concerns. Node can doesn't mean it should with the exception of keeping your stack simpler (a single language). But that's a compromise to achieve a different goal.
I personally like Go more these days because it doesn't have these problems, it's very easy to do concurrency, and it's memory overhead is much lower. This in contrast to my other favorite option, python, which is a nicer language imo, but it's concurrency story is worse and memory overhead is about on par (varying from case to case, but my point being they're both much more than Go).
I imagine I'll get downvoted for participating in the language flame wars but....
I've been working on a NodeJS backend at my main gig for the last two years.
For two years before that I was working on an backend application written in C#.
Based on my experience with those two systems, the answer to the question "When should I use Node for the back end?" should be: Only if your main language is javascript and you don't have the time and/or inclination to learn something else.
For me, working with C# was massively more productive. Static typing, robust async/await, and the fantastic tooling you get with Visual Studio + Resharper are huge benefits. Dynamic typing, callbacks and/or weird promise logic, and dodgy open source libraries which may not be very well documented or maintained are huge downsides for Node JS.
I would never choose to write a new project's backend in Node JS.
Have you tried TypeScript on the backend? I've seen that a couple of times now recently - .NET shops adopting nodejs on the backend via TypeScript and the feedback has been positive.
I used Typescript on the front end a couple of years ago but not on the back end yet. I imagine that it would be better than es6 since there would be some typing. I'd still rather go with C# and not have to deal with callback/promise land.
You are mistaken. The only new syntax ES7 added was the exponentiation operator. async-await was still in stage 3 at the time. It will be in ES2017 (ES8).
Like others have said, callback hell is fixed with async/await, yield/generators, and even lightweight libraries like fibers and promises. Personally, I dislike promises, and I don't use them at all. That said, you have plenty of other choices when it comes to style.
The single-threaded nature of node.js was very intentional and was thought to be a better design choice for a certain class of applications (IO focused, not computation focused) like routers, web servers, and other networked applications.
Single threading was not intentional. It's because they used js, now they're trying to sell it as a feature. They've tried to implement threading several times but it's a huge change to the V8 engine and js isn't designed for it.
Promises/async were needed to make the language usable because it's stuck on a single thread. The normal solution is to just use multiple threads and people have been doing g that for many years in other languages
But, this was intentional. As for them implementing threading, I am not sure about the history here. Was it like: "We used JS and knew we were going to have a ST environment, but because people wanted MT, we tried..."
Or, was it more like: "Let's use js and we'll of course need MT like everything else... oh wait... nvm."?
I second that. JS is singlethreaded by intention, and IMHO it's ok that way and the reason why the ecosystem mostly works and async libraries can be reasoned about. There are JS implementations (like Nashorn on JVM) which are multithreaded, and imho they would be a much poorer choice. Once you have callbacks and multithreading in a single system there are dozens of things you need to care about (from which thread will callback be fired, how to synchronize that with the remaining logic, ...) and the complexity grows immensely. I think that's exactly the scenario that the JS inventors wanted to circumvent.
Java and c# manage threads+async just fine. You're overestimating the difficulty of using then together. In practice you just add the word async or await and go about things normally like in node.
Js is single threaded because it was designed that way, not because it's a good design
I disagree. In my experience from seeing lots of code multithreading issues are one of the most common. E.g. in Android or C# GUI frameworks it's a super common error that people try to manipulate GUI elements from a background that just invoked their callback - which is not allowed. The issues there are typically that people without much experience don't even think about from thread an event can be fired - and what you should do if it's another one than the main thread. Even if you know about these problems it's often not clearly documented what the threading model of libraries is. Afaik the JS creators explicitly intended to avoid these issues by using a singlethreaded model.
The most common use case for node is probably as a web framework. At least in this case multithreading doesn't cause issues in c# or java. You just add an async decorator to your methods and it works.
You're defending the single threaded model as if multithreading is a problem but it's just a feature. you could choose not to use it if you don't mind the performance penalty, just like async.
Node not having multi thread support is definitely a negative.
It was very intentional. The original developer wanted to create an event loop based system because at the time the C hackers had begun to learn how fast those systems could be for the purpose the parent comment mentioned (io bound, network servers, etc.) and instead of using something like lua he chose javascript to give it wider appeal.
JavaScript is single threaded. This wasn't an intentional choice of Node.js, unless you consider @ry picking JavaScript as the basis for your claim. "Non-blocking" code however was the original claimed benefit of Node.js for the reasons you mentioned.
With proper use of promises, async/await and generators, there is no reason for callback hell.
But why would you need threading? 99% of the time will be spent waiting for io. And you can allways spawn a process if you need something computationally heavy.
If you max out the core running your node thread, you are just about to need a second machine and load ballancing anyway.
That's just not true. With SSD's and cheap ram less time than ever is spent waiting on IO. Almost everything these days is CPU bound and it's only going to go more in that direction as the speed disparity between storage and memory shrinks
I tend to get downvoted to hell a lot, so I can't downvote you, because I don't have enough karma.
But when you say "callbacks and/or weird promise logic" I can't help but cringe a little bit. Syntax really depends on what the developer is familiar with.
When you get used to the syntax, and use a decent editor, the syntax is a less important consideration -- a for loop is "fo + enter" in every language. The base libraries and API are important, but I don't consider that syntactical. That said, some languages lend themselves better to certain styles of programming -- but that may be a matter of flavor as well.
If you think you might get down voted, take extra care to ensure you're expressing your thoughts clearly and civilly. There are those who will down-vote regardless, but you can "decrease the attack surface" by writing the best comment you can.
I did the same as you, and my experience couldn't have been more different. It was tremendously freeing to escape the whole .NET framework that came with C#.
My view is that you're always more productive in the language you know better. I find things like being able to use functions as variables tremendously useful in JS. Not to mention the ability to share code between the back and front end of a webapp.
>I find things like being able to use functions as variables tremendously useful in JS
A thing in C# for 9 years now.
> Not to mention the ability to share code between the back and front end of a webapp
Technically possible if you care to do so, but TypeScript + a framework with bindings should be good enough on the front end to not have to completely tear down your conception of what you're doing when you move from front to back.
Wouldn't you agree that a compiled language is typically much easier to maintain than an interpreted one (refactoring, etc). Also, it's been years since I've worked in C#, but I would imagine you could stay in the language but ditch the frameworks.
One does not preclude the other. C# is a pleasure to work with, and a powerful language and environment, but Javascript is the tool for the web-based front end, and a nice language in its own right. Provided a certain discipline, one can use it to write reliable and maintainable code.
I beg to differ with node being the "best choice" for IO intensive ops. Java performance will be better on IO as well, as long as you're using NIO or something like EPOLL native bindings in Netty, which is asynchronous like node but also multi threaded.
The point is that node is not that fast. If performance is paramount don't use it. Node really shines when you need to use client side libraries on the server. The two best uses I've seen is server side rendering of pages and html5 canvas for browser based painting apps
This is a bit of a fine point to make here, but it's not necessary to use stuff like NIO or EPOLL for all IO intensive programs. It depends on the amount of time you expect the threads to be waiting. If the wait times are low, you can expect traditional IO and threads to be quite competitive.
EPOLL / NIO is still great for stuff like HTTP front-ends.
But there's also factors like the slow loris attack, where malicious clients hold a connection open and send a few bytes at a time, never completing the HTTP request. For these attacks, it makes sense for client connections to use the smallest amount of server resources feasible.
In line with my experience as a Java 8 NIO and latest node user, node basically performs identically to the best Netty implementation in IO-bound tasks. That parity could be attributed to relentless optimization of a fundamentally pretty straightforward problem in V8 that finally made it to the latest node.
My experience matches the TechEmpower benchmarks, which you should check out here: https://www.techempower.com/benchmarks/ . They didn't get much discussion when posted.
Fortunes is not IO bound. Plaintext bench definitely is and node is around 8x slower than the fastest frameworks.
Node is nowhere near raw netty performance in most situations and will never be. Js is single threaded, dynamically typed, and doesn't have low enough level access to the OS. Netty has a native network IO interface on linux.
Node is pretty respectable but netty is basically the fastest thing there is unless you're doing C. It even uses native zero copy buffers with the ByteBuf implementation, something js doesn't (and cannot) do with its dynamic typing.
The JVM has had a much longer period of relentless optimization and the language was designed to be well optimized. Js will never escape the performance penalty of dynamic typing and other decisions without a rewrite
I spend most of my time in Go these days, and find that it's goroutine model is perfectly suited for both I/O and CPU-bound services. The runtime decides if a thread is needed, and will spawn one any time you're waiting on a syscall.
I spend most of my time in Go these days, and find that it's goroutine model is perfectly suited for both I/O and CPU-bound services. The runtime decides if a thread is needed, and will spawn one any time you're waiting on a syscall.
This is why node is powerful when used with AWS Lambda, you can treat CPU bound tasks as if they were IO. You can also do this by routing the job to a different processor on the same machine. Node is best when used as a relay or hub between many services and clients. Let those services do the computing work, let node manage everything and do the IO work.
Node is kind of like an airport. Airports let you order food, alcohol, and even other cities. But as soon as you order, all of the work is offloaded to a third party -- the restaurant, the bar, or the airplane -- allowing the airport to handle someone else.
I feel you. My god js is still horrible. Why anyone would willing develop more than they have to in it is beyond me.
Yeah we have ES(x) coming and typescript and node yay! All of the stuff coming to js has existed in better form in other mainstream languages for many years. Even stuff js still doesn't even have on the roadmap like multithreading, true static typing, and compilation
Are mainstream js developers really that ignorant of what is out there to suggest running js on the server all the time?
> Are mainstream js developers really that ignorant of what is out there to suggest running js on the server all the time?
No. At least not the high caliber ones.
There are those that know only know JavaScript and will try to make everything fit. Although, you can say that about people who only know Java, or Python, etc.
Pardon my ignorance, but does Node improve as the V8 engine (or Microsoft's Chakra engine) improves?
Also, when/if GraalVM becomes public, would Node then be more suitable for CPU intensive apps?
I love javascript but never quite grok'd it as a server side language. I wouldn't mind using it, but have never found a good use case and this article hasn't really convinced me to delve into it.
Edit: I have found that it has been pretty neat for some command line integrations, but lately, I have been falling back to Ruby.
Yeah but I doubt it will ever hit parity with c#/Java/go. The lack of static typing and other fundamental languages choices will keep it from ever being as fast as those. V8 and friends were built out of necessity not because js was ever a good lang to begin with.
I really have no idea why anyone would take a language as terribly designed as JavaScript and try to put it everywhere. Non existant typing system, crazy semantics, and lack of true multithreading will always make it second rate to the others
V8 does almost everything JVM does, the problem is mostly in js dynamic typing and weak object implementation. There's a lot of runtime checks that just can't be optimized out. I would expect js to reach maybe a third of JVM performance but thats probably the limit
If you write your javascript in a way that is easy for V8 to JIT, then I think you'll benefit most from progressive enhancements made in the underlying engine. There's a lot of talks and articles on V8 performance, for example:
Surprisingly, very boring, predictably shaped prototypey classes written in the "hidden classes" style they prescribe will JIT compile amazingly well. I think a lot of the fancy uses of JavaScript to roll types with mixins and traits or simply to sidestep needing the 'new' keyword to instantiate objects miss out on lots of performance benefits on V8.
Honestly, where does all the hate for 'new' come from? Prototypey classes work fine once you understand how to roll them/extend them, and 'new' is a real keyword in the language, what's to hate?
I'd still ( and have ) used node for cpu intensive stuff. If you have a long running computation that can be broken down (mine was 500-2000 steps), you can break the single process by `setTimeout(...,0)` the next step, so other stuff can serve pages. Or, you can break it out into a c job.
You should use Node.js for back end when you make WEB APPS and want to deliver real time updates and run background processes. Node.js has a very robust ecosystem that integrates well with front end Javascript.
came from ror/sinatra, but really like the deployment ease of golang, just copy a binary, dont need rvm, ruby interpreter, gems, etc. i think the performance is much better for golang, but i dont like golang's orms and the templating languages really suck relative to haml, etc. i mostly use golang for restful api backends and mobile on the frontend (mobile first), but for dynamic websites, golang is not that interesting.
When the front-end is JavaScript and may share code with the backend or when you find an applicable package in npm. Or when you know JavaScript better than other languages.
One good spot that comes to mind is when you implement "Backend For Frontend" style APIs for your clients in a microservices environment. Assuming you have a single page app in JS, you can have the front-end team own their specific API implementation and have them work in the language they know best. There's often also the possibility to reuse some code between the two.
Apart from that, I'm a JS hater, so I would personally always avoid Node - I neither like the language nor the server-side model, I don't think either one scales well, and there are better solutions out there for the server side (besides the JVM and .NET based stuff in the other comments, I like BEAM-based things like Elixir these days).
87 comments
[ 2.7 ms ] story [ 53.8 ms ] threadHere's a more verbose article on the topic, circa 2013:
https://www.toptal.com/nodejs/why-the-hell-would-i-use-node-...
The real idea is don't do CPU intensive tasks in the event loop thread.
Instead, sometimes you use node native modules, sometimes you separate you child_process.spawn something written in Go, C++, or Rust(,etc), and sometimes you set up a separate work "queue" to pass work either on the same machine or over the network. I've used both kafka, zeromq, or even just files on the s3. A linux domain socket is nice too.
The WebWorkers and other approaches are about how to avoid using the IO thread to do CPU tasks. How the performance of those CPU tasks is depends on other factors. You can use WebAssembly or asm.js code to reach the performance of natively compiled code.
https://github.com/LearnBoost/cluster - one I've used
In node you get sharing at basically the speed of TCP local sockets on the machine. So maybe 5GBps. With natively threaded languages you get sharing at the speed of the cpu cache, orders of magnitude faster
If performance is important enough that multithreading comes into play, don't use node.
- When a Firebase ref changes I listen to the event in Nodejs and update a full text search index elsewhere.
- When a Firebase ref is created I send the appropriate transactional email/push/sms.
- Do data validations before pushing to Firebase.
So in general, I do things that cannot/should not be done on the client-side while still opting for serverless architectures.
PS: Parse.com was great in that it had server-side code that was run on events like object updated/created. The code was NodeJS. In sum, it had lambda-like functionality already built-in. But Parse.com closed shop. Not sure if any of its spin-offs are offering a good service at decent prices.
a) So you reimplemented all of the goodness of twisted in javascript? :) b) and you have to debug that new pile of code? c) with a language (in it's original form) that has a bunch of issues, despite being fun to develop in
Maybe Node with an ES6 backend? Maybe that's better. However, from my perspective, event based development works for some apps but is a total PITA for traditional workloads (websites).
I would think about Node for a messaging use case, or message processing.
I personally like Go more these days because it doesn't have these problems, it's very easy to do concurrency, and it's memory overhead is much lower. This in contrast to my other favorite option, python, which is a nicer language imo, but it's concurrency story is worse and memory overhead is about on par (varying from case to case, but my point being they're both much more than Go).
I've been working on a NodeJS backend at my main gig for the last two years.
For two years before that I was working on an backend application written in C#.
Based on my experience with those two systems, the answer to the question "When should I use Node for the back end?" should be: Only if your main language is javascript and you don't have the time and/or inclination to learn something else.
For me, working with C# was massively more productive. Static typing, robust async/await, and the fantastic tooling you get with Visual Studio + Resharper are huge benefits. Dynamic typing, callbacks and/or weird promise logic, and dodgy open source libraries which may not be very well documented or maintained are huge downsides for Node JS.
I would never choose to write a new project's backend in Node JS.
YMMV.
The single-threaded nature of node.js was very intentional and was thought to be a better design choice for a certain class of applications (IO focused, not computation focused) like routers, web servers, and other networked applications.
Promises/async were needed to make the language usable because it's stuck on a single thread. The normal solution is to just use multiple threads and people have been doing g that for many years in other languages
But, this was intentional. As for them implementing threading, I am not sure about the history here. Was it like: "We used JS and knew we were going to have a ST environment, but because people wanted MT, we tried..."
Or, was it more like: "Let's use js and we'll of course need MT like everything else... oh wait... nvm."?
Js is single threaded because it was designed that way, not because it's a good design
You're defending the single threaded model as if multithreading is a problem but it's just a feature. you could choose not to use it if you don't mind the performance penalty, just like async.
Node not having multi thread support is definitely a negative.
But why would you need threading? 99% of the time will be spent waiting for io. And you can allways spawn a process if you need something computationally heavy.
If you max out the core running your node thread, you are just about to need a second machine and load ballancing anyway.
With noexplicitany and strictnullchecks, you can get really nice, typed code.
Even stringly typed code can be typed now, with keyof.
But when you say "callbacks and/or weird promise logic" I can't help but cringe a little bit. Syntax really depends on what the developer is familiar with.
When you get used to the syntax, and use a decent editor, the syntax is a less important consideration -- a for loop is "fo + enter" in every language. The base libraries and API are important, but I don't consider that syntactical. That said, some languages lend themselves better to certain styles of programming -- but that may be a matter of flavor as well.
From the guidelines:
Please don't bait other users by inviting them to downvote you or announce that you expect to get downvoted.
https://news.ycombinator.com/newsguidelines.html
If you think you might get down voted, take extra care to ensure you're expressing your thoughts clearly and civilly. There are those who will down-vote regardless, but you can "decrease the attack surface" by writing the best comment you can.
Downvotes aren't usually from a lack of civility. They are from saying something that contradicts other people's worldview.
My view is that you're always more productive in the language you know better. I find things like being able to use functions as variables tremendously useful in JS. Not to mention the ability to share code between the back and front end of a webapp.
A thing in C# for 9 years now.
> Not to mention the ability to share code between the back and front end of a webapp
Technically possible if you care to do so, but TypeScript + a framework with bindings should be good enough on the front end to not have to completely tear down your conception of what you're doing when you move from front to back.
But, for instance, IronPython and IronRuby are compiled, yet dynamic, and GHCi is a Haskell interpreter that runs an extremely strong/static language.
The point is that node is not that fast. If performance is paramount don't use it. Node really shines when you need to use client side libraries on the server. The two best uses I've seen is server side rendering of pages and html5 canvas for browser based painting apps
EPOLL / NIO is still great for stuff like HTTP front-ends.
But there's also factors like the slow loris attack, where malicious clients hold a connection open and send a few bytes at a time, never completing the HTTP request. For these attacks, it makes sense for client connections to use the smallest amount of server resources feasible.
My experience matches the TechEmpower benchmarks, which you should check out here: https://www.techempower.com/benchmarks/ . They didn't get much discussion when posted.
Node is nowhere near raw netty performance in most situations and will never be. Js is single threaded, dynamically typed, and doesn't have low enough level access to the OS. Netty has a native network IO interface on linux.
Node is pretty respectable but netty is basically the fastest thing there is unless you're doing C. It even uses native zero copy buffers with the ByteBuf implementation, something js doesn't (and cannot) do with its dynamic typing.
The JVM has had a much longer period of relentless optimization and the language was designed to be well optimized. Js will never escape the performance penalty of dynamic typing and other decisions without a rewrite
I would choose it over Python or Ruby, because Typescript and Flow are great type systems.
Source: lead node dev / CTO since it came out. Currently using Haskell for all new projects.
http://www.purescript.org/
Would you mind saying where you work?
Node is kind of like an airport. Airports let you order food, alcohol, and even other cities. But as soon as you order, all of the work is offloaded to a third party -- the restaurant, the bar, or the airplane -- allowing the airport to handle someone else.
Yeah we have ES(x) coming and typescript and node yay! All of the stuff coming to js has existed in better form in other mainstream languages for many years. Even stuff js still doesn't even have on the roadmap like multithreading, true static typing, and compilation
Are mainstream js developers really that ignorant of what is out there to suggest running js on the server all the time?
No. At least not the high caliber ones.
There are those that know only know JavaScript and will try to make everything fit. Although, you can say that about people who only know Java, or Python, etc.
Also, when/if GraalVM becomes public, would Node then be more suitable for CPU intensive apps?
I love javascript but never quite grok'd it as a server side language. I wouldn't mind using it, but have never found a good use case and this article hasn't really convinced me to delve into it.
Edit: I have found that it has been pretty neat for some command line integrations, but lately, I have been falling back to Ruby.
I really have no idea why anyone would take a language as terribly designed as JavaScript and try to put it everywhere. Non existant typing system, crazy semantics, and lack of true multithreading will always make it second rate to the others
I saw this video (https://www.youtube.com/watch?v=lYGfD2H99Ls) earlier this year, would be interested to see when and if this could be implemented in the mainstream.
http://mrale.ph/v8/resources.html
Surprisingly, very boring, predictably shaped prototypey classes written in the "hidden classes" style they prescribe will JIT compile amazingly well. I think a lot of the fancy uses of JavaScript to roll types with mixins and traits or simply to sidestep needing the 'new' keyword to instantiate objects miss out on lots of performance benefits on V8.
Honestly, where does all the hate for 'new' come from? Prototypey classes work fine once you understand how to roll them/extend them, and 'new' is a real keyword in the language, what's to hate?
i liked the package manager npm, but otherwise i prefer golang all the way for backend code.
Apart from that, I'm a JS hater, so I would personally always avoid Node - I neither like the language nor the server-side model, I don't think either one scales well, and there are better solutions out there for the server side (besides the JVM and .NET based stuff in the other comments, I like BEAM-based things like Elixir these days).