12

I was going through node docs for event loop and I got very confused. It says -

timers: this phase executes callbacks scheduled by setTimeout() and 
setInterval().
I/O callbacks: executes almost all callbacks with the exception of close callbacks, the ones scheduled by timers, and setImmediate().
idle, prepare: only used internally.
poll: retrieve new I/O events; node will block here when appropriate.
check: setImmediate() callbacks are invoked here.
close callbacks: e.g. socket.on('close', ...).

Then in detailed poll phase, they say that it executes timers scheduled with timer and also process i/o events in poll queue. My confusion is taht we already have timer phase and i/o callback phase for those callbacks, then what is the work done by poll phase. It also says that thread may sleep in poll phase but I don't get it properly.
My questions are-

  1. Why poll phase is executing scripts for timers and i/o(s) when we already have timer and i/o callback phase ?
  2. Is it like poll phase executes callbacks on behalf of timer and i/o callback phase and timer and callback phase is only for internal processing no callbacks are executed in this phase ?
  3. Where can we place promises in this loop ? Earlier I thought that promises can be thought simply as callbacks and we can treat them like callbacks only, but in this video, he says that promises goes into an internal event loop, but does not talk in detail.

I am very confused at this point. Any help will be appreciated.

Krrish Raj
  • 1,505
  • 12
  • 28

3 Answers3

9

The poll phase boils down to an asynchronous I/O wait. Libuv will use different APIs depending on the OS but they all generally have the same pattern. I'm going to use select() as an example.

The poll is basically a system call like this:

select(maxNumberOfIO, readableIOList, writableIOList, errorIOList, timeout);

This function blocks. If no timeout value is specified it blocks forever.

The result is that node.js will not be able to execute any javascript as long as there is no I/O activity. This obviously makes it impossible to execute time-based callbacks like setTimeout() or setInterval().

Therefore, what node needs to do before calling such a function is to calculate what value to pass as timeout. It generally does this by going through the list of all timers and figure out the shortest amount of time it can wait for I/O (the next nearest timer) and use that as the timeout value. It basically processes all the timers but not to execute their callbacks, it does it to figure out the wait time.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • What if we are blocked "forever" but some I/O callback schedules a function with `setImmediately`? Would this waiting be interrupted? – Ilya Loskutov Jan 24 '21 at 11:06
  • There is no interrupting the program execution. The C interrupt handler (which is part of the OS - Windows, Linux or MacOS) will register an OS event which can be read later by javascript (node.js, Chrome, Safari, Firefox, Edge etc.) but the javascript engine itself is not interruptable. The interpreter will simply execute forever before attempting to check the OS event and since forever never ends the `setImmediately` callback never gets executed – slebetman Jan 24 '21 at 11:10
  • I've written much more detailed answers related to this: https://stackoverflow.com/questions/29883525/i-know-that-callback-function-runs-asynchronously-but-why/29885509#29885509 and https://stackoverflow.com/questions/34855352/how-in-general-does-node-js-handle-10-000-concurrent-requests/34857298#34857298 and https://stackoverflow.com/questions/61262054/is-there-any-other-way-to-implement-a-listening-function-without-an-infinite-w/61826079#61826079 – slebetman Jan 24 '21 at 11:15
  • And https://stackoverflow.com/questions/65677852/node-js-single-thread-mechanism/65678349#65678349 and https://stackoverflow.com/questions/62970655/is-my-understanding-of-asynchronous-operations-correct/62974386#62974386 and https://stackoverflow.com/questions/19616477/does-javascript-process-using-an-elastic-racetrack-algorithm/19620041#19620041 and https://stackoverflow.com/questions/62165375/do-timers-run-on-their-own-threads-in-node-js/62165526#62165526 – slebetman Jan 24 '21 at 11:16
  • And a few more I've probably forgotten. If you need code to execute on time regardless then you need a thread. For browsers use web workers and for node.js use worker threads – slebetman Jan 24 '21 at 11:17
  • Your answers really cleared up a lot for me. But still I have a little misunderstanding. When `select()` function returns because some I/O event takes place the callback can in this point of time schedule some `setImmediate()` function. In this case does `libuv` recalculate its timeout (set it at 0) before call `select()` again? – Ilya Loskutov Jan 24 '21 at 14:29
  • I asked my question here: https://stackoverflow.com/questions/65869806/can-i-o-callback-setimmediate-interrupt-waiting-for-other-i-o-notifications In any case, thank you for your thoroughgoing answers. – Ilya Loskutov Jan 24 '21 at 14:29
  • @Mergasov Yes. Having actually implemented setTimeout and setInterval type functions for the Ferite programming language (http://ferite.sourceforge.net) that's exactly how I did it. Except you don't need to calculate timeout for setImmediate callbacks - you just call all of them at the end of script execution before calling `select()`. For setTimeout and setInterval you keep a list of times when the callbacks needs to be called and calculate the next timeout – slebetman Jan 24 '21 at 17:09
2

Nodejs has 5 major phases.
1) timers phase.
2) pending call back phase.
3) poll phase
4) check (set immediate).
5) close

Answer to your questions.
1)The call backs to timers and check phase are executed in their respective phases and not in poll phase.

2)All the I/o related call backs and other are executed in the poll phase. The pending call back phase is only for system level callbacks like tcp errors, none of our concern

3)After each phase, node js has an internal event loop which resolves all the process.nextTick callbacks, and another smaller event loop which executes the resolved promises then callbacks i.e Promise.resolve.then() callbacks.

Sagar Chaudhary
  • 1,343
  • 7
  • 21
  • "2)All the I/o related call backs and other are executed in the poll phase." - what is "other" here that you are referring to? – Keerthi Dec 15 '21 at 05:53
1

I was just reading about that myself. As far as the timers are concerned the documentation about the event loop gives a decent answer in the form of an example. Say a setTimeout timer is set to trigger after 100ms but an I/O process is in progress (in the polling phase) and requires more than 100ms to execute, say 150ms. Once it is finished the polling phase will then wrap back to the timer phase and execute the setTimeout later than the expected 100ms, at 150ms.

Hope that helps answer how the polling phase relates to the timer phase. In essence the polling phase, as I understand it, can 'make the decision' to run the timer phase again if necessary.

  • found this discussion on reddit that seems illuminating still trying to fully grok it https://www.reddit.com/r/node/comments/75m6cx/libuv_how_is_the_poll_phase_differentiated_from/?st=ja484wrx&sh=4c279c13 – Andreas Dilaveris Nov 17 '17 at 19:07