8

Take the following code taken from the nodejs event loop documentation :

// timeout_vs_immediate.js
setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

According to the documentation :

For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process.

Why is the above statement true ? Is it because the nodejs runtime actually employs more than one thread to pick out the callbacks that have to be executed.

What my intuition says: there are two threads that execute callbacks for setTimeout and setImmediate so when both of them are available this leads to a race condition, and thus the output will be non-deterministic.

Is it correct ? Or is there any other reason for which this is non-deterministic ?

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
ng.newbie
  • 2,807
  • 3
  • 23
  • 57
  • I know this is a bit long but there is no better explanation than [here](https://blog.risingstack.com/node-js-at-scale-understanding-node-js-event-loop/) – Orelsanpls Aug 29 '17 at 08:41
  • Good question! I've read the node.js event loop document very carefully but failed to find the explanation. It seems the document only tell us it-would-be-non-deterministic, but never mention why. – shaochuancs Aug 29 '17 at 10:13
  • @shaochuancs do you think it is non-deterministic by design ? – ng.newbie Aug 29 '17 at 12:22
  • @ng.newbie No, I don't think it's by design. I guess this non-deterministic behaviour can be explained by some internal Node.js mechanism. Unfortunately, no document/article is found. – shaochuancs Aug 29 '17 at 12:42

1 Answers1

4

Essentially, two things happen:

  1. setTimer(0..) gets converted into setTimer(1..)
  2. before the (next) event loop tick begins, node/libuv has to perform a clock_gettime() to get the current time from the system. The time taken for this system call is non deterministic as it depends on the system load at that time. Now, if clock_gettime() took more than 1ms, the setTimer callback will run (#), else event loop continues to next phase (##).

    • In case (#), setTimeout(0,..) callback is run before setImmediate()
    • In case (##), it is otherwise.

Reference: https://github.com/nodejs/help/issues/392#issuecomment-305969168

human
  • 2,250
  • 20
  • 24