Recently a friend of mine who is not a programmer, asked:
what is so different about Nodejs?
As we tried to explain, an analogy came to @mbalex99 and me: a crowded bar.
Imagine a crowded bar with people ordering beer from the tap. Each part of this process corresponds to a server answering requests
- a person ordering a beer - a web request
- bartender - language runtime (Nodejs, C++, Java, etc)
- tap line - operating system resource, like a file or a socket
Here is the typical non-Nodejs situation
- A client orders a beer.
- A bartender pushes the tap lever AND waits. The client and the bartender are waiting for the glass to be filled. Other customers are standing in line and wait their turn.
- Once the glass is full, the bartender gives it to the client.
We can scale the system by processing multiple requests in parallel (there are several taps in the bar) by hiring more bartenders, each one serving single client at a time. The situation is both expensive, because there might not be enough customers, and the bartenders soon start getting in each other's way. Sometimes one bartender grabs a tap, while another grabs an empty glass, and they wait for the other resource - the deadlock situation. This is how non-Nodejs runtimes scale - by creating heavy parallel threads or processes.
Nodejs approach
Here is what makes the Node's single bartender different
- A client orders a beer.
- The single bartender pushes the tap lever.
- Without waiting the bartender asks the second customer, AND opens second tap, etc. As many customers will be waiting as there are taps.
- As soon as first glass is full, the bartender gives it to the customer, fulfilling the request.
A single bartender thus is limited by the number of taps (operating system resources), and can process many clients in parallel without the overhead of multiple employees trying to work in a limited space.
JavaScript makes it possible
Node's asynchronous nature is made possible by the JavaScript's single event queue and simple callback setup. Listening for HTTP requests and responding with messages is as easy as processing browser button clicks:
1 | $('button').on('click', function () { |
There are no multiple threads to block each other, no shared or synchronized memory access, no weird language constructs - just plain callbacks and using operating system resources.
Nodejs limitation
If a single bartender spends too long with each client (for example chatting before pushing the tap lever), everything slows down. For example, other clients might be waiting for their beer glasses, which are already full. Node is great for input / output intensive tasks, but not for lots of processing (like video encoding). Luckily there are work arounds, like starting a cluster of Node processes, or spawning an external process for a computationally intensive task.