Having read through dozens of articles and documents describing the Node.js event loop, such as the one provided by Node.js themselves: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
I simply cannot wrap my head around this: WHY does the event loop require several phases, each with their own callback queues?
All the documents and articles describe the phases of the loop in terms of "this phase does so and so and executes callbacks set with X or Y", but never really expound on WHY these separate queues are necessary in the first place.
Why would the callbacks of a setTimeout()
or setImmediate()
or socket closings need to be executed at a different point than the polling phase where supposedly the vast majority of callbacks are executed?
if the callback queue in the polling phase is exhausted before moving to the next phase anyway, why not just have one queue that is interrupted for whatever non-queue related actions are performed in the other phases?
Event loop is an endless loop, which waits for tasks, executes them and then sleeps until it receives more tasks. The event loop executes tasks from the event queue only when the call stack is empty i.e. there is no ongoing task. The event loop allows us to use callbacks and promises.
The Event Loop contains six main phases: timers, I/O callbacks, preparation / idle phase, I/O polling, setImmediate() callbacks execution, and close events callbacks.
Event Loop uses Single Thread only. It is main heart of Node JS Platform Processing Model. Even Loop checks any Client Request is placed in Event Queue.
It's single threaded, so it doesn't need to spawn a new thread for each new incoming connection. Behind the event-loop (which is in fact single threaded), there is a "Non blocking Worker". This thing is not single threaded anymore, so (as far as I understood) it can spawn a new thread for each task.
It does not have to be like this. Everything could be in a single queue, but it's safe to assume that the creators of NodeJS had some reasons to do it the way they did it. We know that Javascript is single-threaded. So, if you say that you want an event to happen 5 seconds from now, then there will be no other thread to ensure that the event really runs at the specified time. On the other hand, it's impossible to determine beforehand whether a given function will last 0.1 second, of 4.5 seconds.
So, even though they didn't have to do it the way they did, there is an objective benefit in putting the timer functionalities in a high priority queue and handle them first. This way the system will know whether something should be urgently executed and can execute it urgently before handling everything else. Also, the system will know how much time it has before the next timer event is to be executed.
Pending callbacks are what the system was waited for, so it's very useful and there is an objective benefit in putting it into a second queue, which has smaller priority than timers, but higher than other things.
As we can see at the poll section, its behavior depends on the timers queue's status.
check will execute some events specified in the poll phase.
The close callbacks will handle callback interruption in its appropriate case.
So, we can understand all these aspects from the article, even though, I must admit that it needs more thinking than one would expect from an article which aims to clarify it.
In short, it does not have to work the way it works. There are infinitely many possible ways which differ from this one and would be effective.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With