I'm running on node 8.11
this test script:
let end = false;
let i = 0;
setInterval(() => { i++; }).unref();
let k = 0;
async function loop() {
k++
if (end === false)
setImmediate(loop);
}
console.time('test');
loop()
.then(() => {
setTimeout(() => {
end = true;
console.log('interval', i);
console.log('recursion', k);
console.timeEnd('test');
}, 1000);
})
And the output is:
interval 997
recursion 824687
test: 1001.831ms
But, if I comment these two lines:
// if (end === false)
// setImmediate(loop);
The results are:
interval 537
recursion 1
test: 1003.882ms
I studied hard the phases of nodejs but I don't understand why a setImmediate
should impact on the results of the interval function.
Do you have some explanations?
That's because the timers on nodejs are not precise in the sense that they are just events in the event loop and so they can't know exactly when they will be triggered, that's why setTimeout says that it will execute at least after the time you provided.
The timeout interval that is set cannot be relied upon to execute after that exact number of milliseconds. This is because other executing code that blocks or holds onto the event loop will push the execution of the timeout back. The only guarantee is that the timeout will not execute sooner than the declared timeout interval.
When you set the setImmediate, you are filling the event loop with a lot of immediate events and so you are pushing the timeout ones back on the queue.
Have in mind that event loop cycles haven't the same (an exact) duration in time, so even if you think setImmediate shouldn't affect timers, you are extending the event cycles duration in time.
Interesting articles:
https://nodejs.org/en/docs/guides/timers-in-node/
Edit: as you pointed, in your case it is the opposite, there are more iterations when using setImmediate. In that case it may be related to the speed of the event loop being dynamic depending on the load of the program.