Si está familiarizado con la programación JavaScript del lado del cliente, es posible que haya utilizado las funciones SetTimeout y SetInterval, que permiten retrasos durante un período de tiempo antes de ejecutar la función. Por ejemplo, el siguiente código, una vez cargado en la página web, después de 1 segundo, se agregará "Hola" después del documento de la página:
La copia del código es la siguiente:
var OneSecond = 1000 * 1; // un segundo = 1000 x 1 ms
setTimeOut (function () {
document.write ('<p> hola allí. </p>');
}, OneSecond);
y SetInterval permite la ejecución repetida de funciones a intervalos de tiempo especificados. Si se inyecta el siguiente código en la página web, provocará que se agregue la siguiente oración "hola" al documento de la página cada segundo:
La copia del código es la siguiente:
var OneSecond = 1000 * 1; // un segundo = 1000 x 1 ms
setInterval (function () {
document.write ('<p> hola allí. </p>');
}, OneSecond);
Debido a que la web se ha convertido durante mucho tiempo en una plataforma para construir aplicaciones, en lugar de una página estática simple, este tipo de demanda similar está emergiendo cada vez más. Estas funciones de planificación de tareas ayudan a los desarrolladores a implementar la verificación periódica de los formularios, retrasar la sincronización de datos remotos o las interacciones de UI que requieren respuestas retrasadas. El nodo también implementa estos métodos en su totalidad. En el lado del servidor, puede usarlos para repetir o retrasar la ejecución de muchas tareas, como la expiración de caché, la limpieza del grupo de conexión, la vencimiento de la sesión, las encuestas y más.
Ejecutar usando la función de retraso de setTimeOut
SetTimeOut puede crear un plan de ejecución que ejecute la función especificada una vez en un momento determinado en el futuro, como:
La copia del código es la siguiente:
VAR TIMEOUT_MS = 2000; // 2 segundos
VAR TIMEOUT = SETTIMEOUT (function () {
console.log ("¡Agotado!");
}, timeout_ms);
Al igual que el cliente JavaScript, SetTimeout acepta dos parámetros. El primer parámetro es la función que debe retrasarse, y el segundo parámetro es el tiempo de retraso (en milisegundos).
SetTimeout devuelve un mango de tiempo de espera, que es un objeto interno. Puede usarlo como parámetro para llamar a ClearTimeOut para cancelar el temporizador. Excepto que este mango no tiene efecto.
Use ClearTimeOut para cancelar el plan de ejecución
Una vez que se obtiene el control de tiempo de espera, puede usar ClearTimeOut para cancelar el plan de ejecución de funciones, así:
La copia del código es la siguiente:
VAR TIMEOUTTIME = 1000; // un segundo
VAR TIMEOUT = SETTIMEOUT (function () {
console.log ("¡Agotado!");
}, tiempo de espera);
ClearTimeOut (tiempo de espera);
En este ejemplo, el temporizador nunca se activará y no generará las palabras "¡Tiempo de espera!". También puede cancelar el plan de ejecución en cualquier momento en el futuro, como el siguiente ejemplo:
La copia del código es la siguiente:
VAR TIMEOUT = SetTimeOut (function a () {
console.log ("¡Agotado!");
}, 2000);
setTimeout (función b () {
ClearTimeOut (tiempo de espera);
}, 1000);
El código especifica dos funciones A y B que se ejecutan retrasadas. La función A se planea ejecutarse después de 2 segundos, y se planea ejecutarse después de 1 segundo, porque la función B se ejecuta primero, y cancela el plan de ejecución de A, por lo que A nunca se ejecutará.
Desarrollar y cancelar el plan de ejecución repetitivo de la función
SetInterval es similar a SetTimeOut, pero ejecutará repetidamente una función en un intervalo de tiempo especificado. Puede usarlo para activar periódicamente un programa para completar algunas otras tareas que deben repetirse, como limpiar, recopilar, registrar, obtener datos, encuestas, etc.
El siguiente código emitirá un "tick" a la consola cada segundo:
La copia del código es la siguiente:
período var = 1000; // 1 segundo
setInterval (function () {
console.log ("tick");
}, período);
Si no desea que se ejecute para siempre, puede usar ClearInterval () para cancelar el temporizador.
SetInterval Devuelve un mango del plan de ejecución, que se puede usar como parámetro para ClearInterval para cancelar el plan de ejecución:
La copia del código es la siguiente:
var interval = setInterval (function () {
console.log ("tick");
}, 1000);
// ...
ClearInterval (intervalo);
Use Process.NextTick para retrasar la ejecución de la función a la siguiente ronda del bucle de eventos
A veces, el programador de JavaScript del cliente usa SetTimout (devolución de llamada, 0) para retrasar la tarea por un corto período de tiempo. El segundo parámetro es 0 milisegundos. Le dice a JavaScript que ejecute esta función de devolución de llamada inmediatamente después de que se procesen todos los eventos pendientes. A veces, esta técnica se utiliza para retrasar la ejecución de operaciones que no necesitan realizarse de inmediato. Por ejemplo, a veces debe comenzar a reproducir animaciones o hacer otros cálculos después de que se procese el evento del usuario.
En el nodo, al igual que el significado literal de "Event Loop", el bucle de eventos se ejecuta en un bucle que maneja las colas de eventos, y cada ronda en el trabajo de bucle de eventos se llama tick.
Puede llamar a la función de devolución de llamada una vez cada vez que el bucle de eventos se inicia la siguiente ronda (siguiente tick), que es exactamente el principio de proceso.
Al usar Process.NextTick (devolución de llamada) en lugar de SetTimeOut (devolución de llamada, 0), su función de devolución de llamada se ejecutará inmediatamente después de que se procese el evento en la cola. Es mucho más rápido que la cola de tiempo de espera de JavaScript (medida por el tiempo de la CPU).
Puede retrasar la función hasta el siguiente bucle de evento y ejecutarla así:
La copia del código es la siguiente:
Process.NextTick (function () {
My_EXPensive_Computation_Function ();
});
Nota: El objeto de proceso es uno de los pocos objetos globales en el nodo.
Bucle de eventos de bloqueo
El tiempo de ejecución de Node y JavaScript utiliza un bucle de eventos de un solo hilo. Cada bucle, el tiempo de ejecución usa la función de devolución de llamada para manejar el siguiente evento en la cola. Cuando se ejecuta el evento, el bucle de eventos obtiene el resultado de ejecución y procesa el siguiente evento, repitiendo esto hasta que la cola del evento esté vacía. Si una de las devoluciones de llamada tarda mucho en ejecutarse, el bucle de eventos no puede manejar otros eventos pendientes durante ese tiempo, lo que puede hacer que la aplicación o servicio sean muy lentos.
Al procesar eventos, si se utilizan funciones sensibles a la memoria o sensibles al procesador, el bucle de eventos se volverá lento y se acumulará una gran cantidad de eventos, que no se pueden procesar a tiempo, o incluso bloquear la cola.
Vea el siguiente ejemplo de bucle de eventos de bloqueo:
La copia del código es la siguiente:
process.nextTick (function nextTick1 () {
var a = 0;
while (verdadero) {
a ++;
}
});
Process.NextTick (function nextTick2 () {
console.log ("Next tick");
});
setTimeout (function timeOut () {
console.log ("Tiempo de espera");
}, 1000);
En este ejemplo, las funciones de NextTick2 y TimeOut no tienen la oportunidad de ejecutar sin importar cuánto tiempo esperen, porque el bucle de eventos está bloqueado por el bucle Infinite en la función NextTick, y no se ejecutará incluso si la función de tiempo de espera está programada para ejecutarse después de 1 segundo.
Cuando se usa SetTimout, las funciones de devolución de llamada se agregan a la cola del plan de ejecución, y en este caso ni siquiera se agregan a la cola. Aunque este es un ejemplo extremo, puede ver que ejecutar una tarea sensible al procesador puede bloquear o ralentizar el bucle del evento.
Salir del bucle de eventos
Usando Process.NextTick, una tarea no crítica se puede posponer en la siguiente ronda del bucle de eventos (tick) antes de la ejecución, lo que puede liberar el bucle de eventos para que pueda continuar ejecutando otros eventos pendientes.
Vea el siguiente ejemplo. Si planea eliminar un archivo temporal, pero no desea que la función de devolución de llamada del evento de datos espere esta operación IO, puede retrasarlo así:
La copia del código es la siguiente:
stream.on ("data", function (data) {
stream.end ("mi respuesta");
Process.NextTick (function () {
fs.unlink ("/path/to/file");
});
});
Use setTimeout en lugar de setInterval para garantizar la serialidad de la ejecución de la función
Supongamos que está planeando diseñar una función llamada my_async_function, que puede hacer algunas operaciones de E/S (como archivos de registro de análisis) y tiene la intención de hacer que se ejecute periódicamente. Puede implementarlo con SetInterval así:
La copia del código es la siguiente:
intervalo var = 1000;
setInterval (function () {
my_async_function (function () {
console.log ('my_async_function terminado!');
});
}, intervalo); // Nota del traductor: Agregué el "intervalo" anterior y el autor debería haberse perdido debido a un error tipográfico
Debe poder asegurarse de que estas funciones no se ejecuten simultáneamente, pero si usa SetInterval no puede garantizar esto. Si la función my_async_function ejecuta un milisegundo más largo que las variables de intervalo, se ejecutarán simultáneamente, en lugar de seriamente en secuencia.
Nota del traductor: (El traductor agrega la parte siguiente, no el contenido del libro original)
Para facilitar la comprensión de esta parte del contenido, puede modificar el código del autor para que pueda ejecutarse:
La copia del código es la siguiente:
intervalo var = 1000;
setInterval (function () {
(función my_async_function () {
setTimeOut (function () {
console.log ("1");
}, 5000);
}) ();
},intervalo);
Ejecute este código y encontrará que después de esperar 5 segundos, "Hola" se emite cada 1 segundo. Esperamos que después de que se haya ejecutado la actual My_async_Function (tomada 5 segundos), espere 1 segundo antes de ejecutar el siguiente my_async_function, y el intervalo entre cada salida debe ser de 6 segundos. Este resultado se debe a que my_async_function no se ejecuta en serie, sino que se ejecuta al mismo tiempo.
Por lo tanto, necesita una forma de forzar el intervalo entre el final de una ejecución de un my_async_function y el inicio de la ejecución de la siguiente my_async_function es exactamente el tiempo especificado por la variable de intervalo. Puedes hacer esto:
La copia del código es la siguiente:
intervalo var = 1000; // 1 segundo
(FUNTIL SHECK () {// Línea 3
setTimeout (function do_it () {
my_async_function (function () {// línea 5
console.log ('Async está hecho!');
cronograma();
});
}, intervalo);
} ()); // Línea 10
En el código anterior, se declara una función llamada Anexo (línea 3), y se llama inmediatamente después de la declaración (línea 10). La función de programación ejecutará la función do_it después de 1 segundo (especificada por intervalo). Después de 1 segundo, se llamará a la función my_async_function en la línea 5. Cuando se ejecute, llamará a su propia función anónima de devolución de llamada (línea 6). Esta función anónima de devolución de llamada restablecerá el plan de ejecución de DO_IT nuevamente y dejará que se ejecute nuevamente después de 1 segundo, de modo que el código comience en serie y continuamente ejecutarse continuamente.
resumen
Puede usar la función SetTimeOut () para preestablecer el plan de ejecución de la función y cancelarlo con la función ClearTimeOut (). También puede usar SetInterval () para ejecutar una determinada función periódicamente repetidamente. En consecuencia, puede usar ClearInterval () para cancelar este plan de ejecución repetido.
Si el bucle de eventos se bloquea utilizando una operación sensible al procesador, las funciones que se planearon originalmente se ejecutarán se retrasarán y nunca se ejecutarán. Así que no use operaciones sensibles a la CPU dentro del bucle de eventos. Además, puede usar Process.NextTick () para retrasar la ejecución de la función hasta la siguiente ronda del bucle de eventos.
Al usar E/S y SetInterval () juntos, no puede garantizar que solo haya una llamada pendiente en cualquier momento, pero puede usar funciones recursivas y funciones de setTimeOut () para evitar este complicado problema.