¿Cómo funciona setTimeout en Node.JS?

112

Supongo que una vez que se ejecuta está en la cola, pero en la cola, ¿hay alguna garantía de que se invocará exactamente después de X milisegundos? ¿O lo retrasarán otras tareas pesadas en la parte superior de la cola?

MyCodeGone
fuente
14
Ningún sistema operativo que no sea en tiempo real hará posible que exista una garantía de precisión seria. Todo tipo de cosas en el sistema pueden (y se interpondrán) en el camino del mecanismo del temporizador.
Puntiagudo

Respuestas:

174

La semántica de setTimeout es aproximadamente la misma que en un navegador web: el tiempo de espera arg es un número mínimo de ms para esperar antes de ejecutar, no una garantía. Además, pasar 0, un no número o un número negativo, hará que espere un número mínimo de ms. En Node, esto es 1 ms, pero en los navegadores puede llegar a 50 ms.

La razón de esto es que JavaScript no se apropia de JavaScript. Considere este ejemplo:

setTimeout(function () {
  console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')

El flujo aquí es:

  1. programe el tiempo de espera para 100 ms.
  2. ocupado, espere 5000ms.
  3. volver al bucle de eventos. comprobar si hay temporizadores pendientes y ejecutar.

Si este no fuera el caso, entonces podría hacer que un bit de JavaScript "interrumpa" a otro. Tendríamos que configurar mutex y semaphors y demás, para evitar que un código como este sea extremadamente difícil de razonar:

var a = 100;
setTimeout(function () {
  a = 0;
}, 0);
var b = a; // 100 or 0?

La ejecución de un solo subproceso de JavaScript de Node hace que sea mucho más sencillo trabajar con él que con la mayoría de los otros estilos de concurrencia. Por supuesto, la compensación es que es posible que una parte del programa que se comporte mal bloquee todo con un bucle infinito.

¿Es este un demonio mejor para luchar que la complejidad de la prevención? Eso depende.

isaacs
fuente
20
Obtienes un +1 por el console.logmensaje excepcionalmente preciso .
Financia la demanda de Monica
Me gusta cómo escribiste en mayúsculas el TIEMPO en tu cadena. Muy buena explicación !!!
Alisson
43

La idea de no bloqueo es que las iteraciones de bucle sean rápidas. Por lo tanto, iterar para cada tick debería tomar un tiempo lo suficientemente corto como para que setTimeout sea exacto dentro de una precisión razonable (fuera de tal vez <100 ms aproximadamente).

En teoría, aunque tienes razón. Si escribo una aplicación y bloqueo la marca, setTimeouts se retrasará. Entonces, para responder a su pregunta, ¿quién puede asegurar que setTimeouts se ejecute a tiempo? Usted, al escribir código sin bloqueo, puede controlar el grado de precisión hasta casi cualquier grado razonable de precisión.

Siempre que javascript sea "de un solo subproceso" en términos de ejecución de código (excluyendo a los trabajadores web y similares), eso siempre sucederá. La naturaleza de un solo subproceso es una gran simplificación en la mayoría de los casos, pero requiere el lenguaje sin bloqueo para tener éxito.

Pruebe este código en su navegador o en el nodo, y verá que no hay garantía de precisión, al contrario, el setTimeout llegará muy tarde:

var start = Date.now();

// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);

// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}

A menos que el intérprete optimice el bucle (lo que no sucede en Chrome), obtendrá algo por miles. Retire el lazo y verá que es 500 en la nariz ...

davin
fuente
9

La única forma de garantizar que se ejecute el código es colocar su lógica setTimeout en un proceso diferente.

Use el módulo de proceso hijo para generar un nuevo programa node.js que haga su lógica y pase datos a ese proceso a través de algún tipo de flujo (tal vez tcp).

De esta manera, incluso si se está ejecutando algún código de bloqueo largo en su proceso principal, su proceso hijo ya se inició y colocó un setTimeout en un nuevo proceso y un nuevo hilo y, por lo tanto, se ejecutará cuando lo espera.

La complicación adicional se encuentra a nivel de hardware donde tiene más subprocesos en ejecución que procesos y, por lo tanto, el cambio de contexto causará retrasos (muy menores) en el tiempo esperado. Esto debería ser insignificante y, si importa, debe considerar seriamente lo que está tratando de hacer, por qué necesita tal precisión y qué tipo de hardware alternativo en tiempo real está disponible para hacer el trabajo.

En general, el uso de procesos secundarios y la ejecución de múltiples aplicaciones de nodo como procesos separados junto con un balanceador de carga o almacenamiento de datos compartido (como redis) es importante para escalar su código.

Raynos
fuente
9

setTimeoutes una especie de Thread , mantiene una operación durante un tiempo determinado y la ejecuta.

setTimeout(function,time_in_mills);

aquí el primer argumento debería ser un tipo de función; como ejemplo, si desea imprimir su nombre después de 3 segundos, su código debería ser algo como el siguiente.

setTimeout(function(){console.log('your name')},3000);

El punto clave para recordar es, lo que sea que quieras hacer usando el setTimeoutmétodo, hazlo dentro de una función . Si desea llamar a algún otro método analizando algunos parámetros, su código debería verse como a continuación:

setTimeout(function(){yourOtherMethod(parameter);},3000);
Ashana.Jackol
fuente
8

setTimeout(callback,t)se utiliza para ejecutar la devolución de llamada después de al menos t milisegundos . El retraso real depende de muchos factores externos, como la granularidad del temporizador del sistema operativo y la carga del sistema.

Por lo tanto, existe la posibilidad de que se llame un poco después del tiempo establecido, pero nunca antes.

Un temporizador no puede durar más de 24,8 días.

Siva Prakash
fuente