Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

431
Vistas
How is timing of `setImmediate()` and `setTimeout()` bound by the performance of the process?

I am confused by the following paragraph of the Node.js documentation.

setImmediate() vs setTimeout()

... The order in which the timers are executed will vary depending on the context in which they are called. If both are called from within the main module, then timing will be bound by the performance of the process (which can be impacted by other applications running on the machine).

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:

It proceeds to show the following example

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

setImmediate(() => {
  console.log('immediate');
});
$ node timeout_vs_immediate.js
timeout
immediate

$ node timeout_vs_immediate.js
immediate
timeout

I don't understand what makes the result non-deterministic. Since the timers phase happens before the check phase, shouldn't the callbacks scheduled by setTimeout always execute before those scheduled by setImmediate? I don't think the order of the phases in the event loop would change due to a context switch or something.

The document also states that

However, if you move the two calls within an I/O cycle, the immediate callback is always executed first:

OK, but what makes so-called "I/O cycles" different from the main module?


I know there are a lot of related questions, but all answers merely state this fact by citing the documentation, without explaining where the non-determinism comes into play, so I don't think this is a duplicate.

about 4 years ago · Juan Pablo Isaza
2 Respuestas
Responde la pregunta

0

The actual trick is in the Timeout constructor which is called by setTimeout and which increases times below 1 to 1. Thus setTimeout(fn, 0) is actually equivalent to setTimeout(fn, 1).

When libuv initializes, it starts with timers after updating its internal clock, and when one millisecond already passed till then it's gonna pick up the timer before proceeding to the poll phase (which is followed by the setImmediate phase).


Another interesting observation is that multiple timers might also run before and after setImmeadiate:

setTimeout(() => console.log('timer'), 1);
setTimeout(() => console.log('timer'), 1);
setImmediate(() => console.log('immediate'));
// can produce:
// timer
// immediate
// timer

That's because setTimeout calls getLibuvNow internally, which will call env->GetNow() and which not only gets the current time of libuv, but also updates it. Thus it might happen that the timer get put into the timer queue with different due times, and thus the timer phase will only pick up some of them.

OK, but what makes so-called "I/O cycles" different from the main module?

The main module gets run before libuv is initialized, whereas most other code will run in the poll phase of the libuv loop. Thus the main module initialization is followed by the timer phase, whereas the poll phase is followed by the 'check handles' phase, which among others runs the setImmediate callbacks. Thus usually in the main module timers would run before immediates (if they're due) and if scheduled in callbacks, immediates would run before timers.

about 4 years ago · Juan Pablo Isaza Denunciar

0

I'll write an aswer as well for visibility, since it's a good question and node documentation indeed is misleading and I had to dig a bit to find some resources as well...

This question was answered here (accepted answer) very well with a performance benchmark testing..

But the actual explaination can be found in another answer that points to this article which explains the event loop better.

event loop explained

difference explained

Also, read this answer (this one is the best one, it goes through the internal code and explains which section is platform dependant and time consuming of the CPU and generates the non-determinism and also the fact that 0 is transformed into 1 internally for setTimeout) to an issue raised on nodejs asking the same question which seems to explain it even further.

One more important things to note is setTimeout when set to 0 is internally converted to 1.

This call to uv__hrtime is platform dependent and is cpu-time-consuming work as it makes system call to clock_gettime. It's is impacted by other application running on the machine.

If the preparation before the first loop took more than 1ms then the Timer Phase calls the callback associated with it. If it's is less than 1ms Event-loop continues to next phase and runs the setImmediate callback in check phase of the loop and setTimeout in the next tick of the loop.

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda