Home > database >  NodeJS setImmediate loop: Is only one setImmediate callback executed per iteration of the event loop
NodeJS setImmediate loop: Is only one setImmediate callback executed per iteration of the event loop

Time:02-04

function loop() {
  // Anything you want to run in a loop can be here

  setImmediate(loop);
}

loop();

In this case, a setImmediate callback is calling another setImmediate whose callback is eventually to the queue (of the "Check" phase). Thus loop() runs repeatedly

Does only one setImmediate callback run per iteration of the event loop? i.e. does loop() only run once per iteration of the event loop?

I often hear that setImmediate is used to run a callback on the next "tick" or iteration of the event loop

However, the official Node documentation on the event loop (https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/) says:

"generally, when the event loop enters a given phase, it will perform any operations specific to that phase, then execute callbacks in that phase's queue until the queue has been exhausted or the maximum number of callbacks has executed."

This makes me think that potentially multiple setImmediate callbacks are run per iteration of the event loop. If this is the case, how can we know how many setImmediate callbacks are executed per "tick"?

Thanks for your help!

CodePudding user response:

Considering loop terminates for a certain condition. The setImmediate() callback will call every time loop's execution ends. As the doc:

setImmediate() is designed to execute a script once the current poll phase completes.

In simple terms, its a callback for the function that you pass, which will execute for every time at the of it's execution.

Consider the following example, you will observe that in the output currentCount value increments when the function ends or as the doc says, at every 'tick'.

const count = 5;
let currentCount = 0;
const array = [];

function loop() {
  console.log('start', currentCount);
  let a = setImmediate((...args) => {
    if (currentCount == count) {
      array.forEach((b) => clearImmediate(b));
    } else {
      console.log(...args, currentCount);
      setTimeout(loop, 1000);
    }
  }, 'data');
  currentCount  ;
  array.push(a);
  console.log('end', currentCount);
}

loop();

Output:

❯ node index.js
start 0
end 1
data 1
start 1
end 2
data 2
start 2
end 3
data 3
start 3
end 4
data 4
start 4
end 5

CodePudding user response:

I believe that for the setImmediate loop code snippet in the original question that there is only one setImmediate callback per iteration of the event loop

I ran an example below that helped resolve this in my mind and hope this is correct:

function loop() {
    console.log('setImmediate loop');

    setImmediate(loop);
}

loop();

setTimeout(() => {
    console.log('setTimeout');

    process.exit();
}, 3); // You can adjust the timeout duration for more setImmediate callbacks before setTimeout's callback is called
# Output
setImmediate loop
setImmediate loop
setImmediate loop
setImmediate loop
setImmediate loop
setImmediate loop
setImmediate loop
setImmediate loop
setImmediate loop
setImmediate loop
setTimeout

This seems to suggest that only one (or at least not many) setImmediate callback runs per tick of the event loop. Otherwise, if the setImmediate loop was starving the event loop (with countless setImmediate callbacks running per tick of the event loop), setTimeout's callback would be blocked. I doubt that 10 callbacks is the hard limit or "maximum number of callbacks" mentioned in the official Node documentation:

"generally, when the event loop enters a given phase, it will perform any operations specific to that phase, then execute callbacks in that phase's queue until the queue has been exhausted or the maximum number of callbacks has executed."

Moreover, by adjusting the setTimeout duration, you can vary the number of setImmediate loop console logs before the setTimeout callback. This confirms that a hard limit or maximum number of callbacks is not being reached

In summary, it seems that setImmediate()'s called during the "Poll" phase won't have their callbacks run until subsequent event loop ticks. In contrast, immediately resolved promises or process.nextTick()'s called while the microtask or nextTick queue is being processed will have their callbacks run before proceeding to the next stage of the event loop

  • Related