Node.js seems to be the popular thing these days. It seems to be everywhere and hsa a lot of fans. But I have to say it bugs me, it seems that Node.js solved the wrong problem. In the interest of full disclosure I should also say that I have been an Erlang developer for the past 5 years.
In the days before Node.JS many web sites ran on PHP, Ruby or Python. In those languages, in general each connection was handled by a Unix process. This could result in really bad performance under heavy load as the system ended up with a large number of processes stuck in an IO Wait state. And furthermore the Unix scheduler makes context switching a rather expensive process.
When they designed Node.JS they made the assumption that since Context switches are expensive they should be avoided at all costs. This leads to the event loop in Node.JS. The idea of this is that nothing ever blocks and that everything gets a turn to run. But there are some problems with this.
First of all there is nothing structurally to prevent a process from doing something slow that blocks the entire system. Callbacks prevent your code from being IO bound, If your code does something expensive that is CPU bound it can block everything else.
The second problem is that Node.JS does not have a good way to deal with multicore systems. Systems with large numbers of cores are a fact of life. And while desktop CPUS seem to top out at about 10 cores these days the Xeon Platinum series which will ship in Q2 2017 will have up to 28 cores and 56 threads, and if that is not enough then the Xeon Phi - Knights Landing CPUS can go up to 72 cores and 288 threads! In addition many servers may put 2 or 4 of these on one motherboard. You can assume that these numbers will continue to go up over the next few years for the simple reason that the power dissipated by a chip goes up with the 3rd power of its clock speed! So systems like the Xeon Phi / Knights Landing chip which contain a large number of slower cores seem to be an inevitable future.
In order to program these effectively we need a way to spread jobs over a large number of cores and to have features like work stealing. Which is a fancy way of saying that the runtime should be able to move stuff from core to core to keep work loads even.
What would have been a much better solution to all of these issues (and what Erlang does) is to simply write a new process mechanism that makes context switching very cheap. An Erlang process takes a few hundred bytes of memory (vs a few megabytes for a Unix process). In addition it allows good performance on multi core as the runtime can move processes between cores at will.
In addition preemptive scheduling prevents an out of control bit of code from doing much harm. While different schedulers work different at the lowest level they all do about the same thing, which is to make sure that no one process takes over the system, and that everything gets a turn. The Unix process manager makes switching a rather heavy job, because it assumes that different jobs have very different interests and may have nothing to do with each other. But an application server can relax that a little bit and in languages like Erlang and Haskell it can take as few as 20 machine instructions to go from one process to another.
If you want to see how this is done in Elixir I am doing a 4 day workshop in London use discount code finch for £200.00 off!