In a heated debate over technicalities on the internet, you may have heard the argument "Yeah, that may be concurrent but not parallel computing." You're wondering what do they mean anyway? What's the difference? Most importantly, should I care?
As it turns out, Node.js can be categorized into one of these. On the general level, though, as long as you keep in mind that the CPU is pretty much always keeping several balls in the air, you're all good.
More work than there are resources
Let's assume that there is more work to be done than there are resources for doing them. That there are multiple threads or sequences of operations to step through. With only one thread or operation sequence, there isn't much to discuss in terms of concurrency or parallelism.
Concurrent operation means that two computations can both make progress and advance regardless of the other. If there are two threads, for example, then both make progress independently. The second computation doesn't need to wait for the first one to complete before it can be advanced.
If computation is said to be concurrent, then it doesn't necessarily dictate how the concurrency is achieved under the hood. In single-core setup, it is possible that the computations take turns in execution. The CPU might run few instructions from the other thread, then suspend it and switch over to the second and run a few steps from it and so on. This is also called pre-emptive multithreading. It may also be possible that there are more cores available that can be used to run both at the same time. This, in fact, is parallel computation, as we'll see next.
Parallel operation means that two computations are literally running at the same time. At one point in time, both computations advance. There is no taking turns; they advance at the same time. Naturally this is not possible with single-core CPU, but multiple-core architecture is required instead.
It can be said that if computation is parallel, it is also concurrent - since parallel computation also fulfills the definition of concurrent computation.
As long as the event handlers are small and frequently wait for yet more events themselves, all computations (for example fulfilling and serving a HTTP request) can advance one small step at a time - concurrently. This is beneficial in web applications where the majority of the time is spent waiting for I/O to complete. It allows a single Node.js process to handle huge amounts of requests.