javascript - node - setImmediate vs. nextTick
nexttick vue (6)
Como una ilustracion
import fs from ''fs'';
import http from ''http'';
const options = {
host: ''www.stackoverflow.com'',
port: 80,
path: ''/index.html''
};
describe(''deferredExecution'', () => {
it(''deferredExecution'', (done) => {
console.log(''Start'');
setTimeout(() => console.log(''TO1''), 0);
setImmediate(() => console.log(''IM1''));
process.nextTick(() => console.log(''NT1''));
setImmediate(() => console.log(''IM2''));
process.nextTick(() => console.log(''NT2''));
http.get(options, () => console.log(''IO1''));
fs.readdir(process.cwd(), () => console.log(''IO2''));
setImmediate(() => console.log(''IM3''));
process.nextTick(() => console.log(''NT3''));
setImmediate(() => console.log(''IM4''));
fs.readdir(process.cwd(), () => console.log(''IO3''));
console.log(''Done'');
setTimeout(done, 1500);
});
});
dará la siguiente salida
Start
Done
NT1
NT2
NT3
TO1
IO2
IO3
IM1
IM2
IM3
IM4
IO1
Espero que esto pueda ayudar a entender la diferencia.
La versión 0.10 de Node.js se lanzó hoy y presentó setImmediate
. La documentación de cambios de API sugiere su uso al hacer llamadas nextTick
recursivas.
Por lo que dice MDN , parece muy similar a process.nextTick
.
¿Cuándo debo usar nextTick
y cuándo debo usar setImmediate
?
Creo que puedo ilustrar esto muy bien. Dado que se llama a nextTick
al final de la operación actual, llamarla recursivamente puede terminar impidiendo que el bucle de eventos continúe. setImmediate
resuelve esto setImmediate
la fase de verificación del bucle de eventos, permitiendo que el ciclo de eventos continúe normalmente.
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
fuente: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
Observe que la fase de verificación se encuentra inmediatamente después de la fase de sondeo. Esto se debe a que la fase de sondeo y las devoluciones de llamada de E / S son los lugares más probables en los que se setImmediate
llamadas a setImmediate
. Por lo tanto, lo ideal sería que la mayoría de esas llamadas sean bastante inmediatas, pero no tan inmediatas como nextTick
que se comprueba después de cada operación y técnicamente existe fuera del bucle de eventos.
Veamos un pequeño ejemplo de la diferencia entre setImmediate
y process.nextTick
:
function step(iteration) {
if (iteration === 10) return;
setImmediate(() => {
console.log(`setImmediate iteration: ${iteration}`);
step(iteration + 1); // Recursive call from setImmediate handler.
});
process.nextTick(() => {
console.log(`nextTick iteration: ${iteration}`);
});
}
step(0);
Digamos que acabamos de ejecutar este programa y estamos pasando por la primera iteración del bucle de eventos. Llamará a la función de step
con iteración cero. Luego registrará dos manejadores, uno para setImmediate
y otro para process.nextTick
. Luego, setImmediate
esta función recursivamente desde el controlador setImmediate
que se ejecutará en la siguiente fase de verificación. El controlador nextTick
se ejecutará al final de la operación actual, interrumpiendo el bucle de eventos, por lo que, aunque se haya registrado en segundo lugar, se ejecutará primero.
El orden finaliza: nextTick
dispara a medida que finaliza la operación actual, comienza el siguiente ciclo de eventos, se ejecutan las fases normales de los eventos, setImmediate
dispara y recursivamente llama a nuestra función de step
para iniciar el proceso nuevamente. Finaliza la operación actual, se dispara nextTick
, etc.
La salida del código anterior sería:
nextTick iteration: 0
setImmediate iteration: 0
nextTick iteration: 1
setImmediate iteration: 1
nextTick iteration: 2
setImmediate iteration: 2
nextTick iteration: 3
setImmediate iteration: 3
nextTick iteration: 4
setImmediate iteration: 4
nextTick iteration: 5
setImmediate iteration: 5
nextTick iteration: 6
setImmediate iteration: 6
nextTick iteration: 7
setImmediate iteration: 7
nextTick iteration: 8
setImmediate iteration: 8
nextTick iteration: 9
setImmediate iteration: 9
Ahora movamos nuestra llamada recursiva para step
a nuestro controlador nextTick
lugar de setImmediate
.
function step(iteration) {
if (iteration === 10) return;
setImmediate(() => {
console.log(`setImmediate iteration: ${iteration}`);
});
process.nextTick(() => {
console.log(`nextTick iteration: ${iteration}`);
step(iteration + 1); // Recursive call from nextTick handler.
});
}
step(0);
Ahora que hemos movido la llamada recursiva para step
al controlador de nextTick
cosas se comportarán en un orden diferente. Nuestra primera iteración del bucle de eventos se ejecuta y llama step
registrando un controlador setImmedaite
así como un controlador nextTick
. Una vez que finaliza la operación actual, nuestro controlador nextTick
que recursivamente llama a step
y registra otro controlador setImmediate
, así como otro controlador nextTick
. Dado que el controlador nextTick
después de la operación actual, el registro de un controlador nextTick
dentro de un controlador nextTick
hará que el segundo controlador se ejecute inmediatamente después de que finalice la operación actual del controlador. Los controladores nextTick
continuarán nextTick
, evitando que el bucle de eventos actual continúe. nextTick
todos los controladores de nextTick
antes de ver que se setImmediate
un solo controlador setImmediate
.
La salida del código anterior termina siendo:
nextTick iteration: 0
nextTick iteration: 1
nextTick iteration: 2
nextTick iteration: 3
nextTick iteration: 4
nextTick iteration: 5
nextTick iteration: 6
nextTick iteration: 7
nextTick iteration: 8
nextTick iteration: 9
setImmediate iteration: 0
setImmediate iteration: 1
setImmediate iteration: 2
setImmediate iteration: 3
setImmediate iteration: 4
setImmediate iteration: 5
setImmediate iteration: 6
setImmediate iteration: 7
setImmediate iteration: 8
setImmediate iteration: 9
Tenga en cuenta que si no hubiéramos interrumpido la llamada recursiva y la nextTick
cancelado después de 10 iteraciones, las llamadas nextTick
seguirían siendo recurrentes y nunca permitirían que el bucle de eventos continúe a la siguiente fase. Así es como nextTick
puede convertirse en bloqueo cuando se usa recursivamente, mientras que setImmediate
se setImmediate
en el próximo bucle de eventos y establecer otro controlador setImmediate
desde uno no interrumpirá el bucle de eventos actual, lo que le permite continuar ejecutando las fases del bucle de eventos como normal .
¡Espero que ayude!
PD: estoy de acuerdo con otros comentaristas en que los nombres de las dos funciones podrían intercambiarse fácilmente, ya que suena nextTick
parece que se nextTick
en el próximo bucle de eventos en lugar del final del actual, y el final del bucle actual es más " inmediato "que el comienzo del siguiente bucle. Bueno, eso es lo que obtenemos a medida que la API madura y la gente depende de las interfaces existentes.
En los comentarios de la respuesta, no se establece explícitamente que nextTick pasó de Macrosemánticos a Microsemánticos.
antes del nodo 0.9 (cuando se introdujo setImmediate), nextTick operaba al inicio de la siguiente pila de llamadas.
desde el nodo 0.9, nextTick opera al final de la pila de llamadas existente, mientras que setImmediate está al comienzo de la siguiente pila de llamadas
visite https://github.com/YuzuJS/setImmediate para obtener herramientas y detalles
En términos simples, process.NextTick () se ejecutaría en el siguiente tick del ciclo de eventos. Sin embargo, el setImmediate, básicamente, tiene una fase separada que garantiza que la devolución de llamada registrada en setImmediate () se llamará solo después de la llamada de IO y la fase de sondeo.
Consulte este enlace para obtener una buena explicación: https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c
Le recomiendo que consulte la sección de nodejs.org/en/docs/guides/event-loop-timers-and-nexttick dedicada a Loop para obtener una mejor comprensión. Algunos fragmentos tomados de allí:
Tenemos dos llamadas que son similares en lo que concierne a los usuarios, pero sus nombres son confusos.
process.nextTick () se dispara inmediatamente en la misma fase
setImmediate () se activa en la siguiente iteración o ''tick'' de la
bucle de eventos
En esencia, los nombres deben ser intercambiados. process.nextTick () se dispara más inmediatamente que setImmediate (), pero este es un artefacto del pasado que es poco probable que cambie.
Utilice setImmediate
si desea poner en cola la función detrás de las devoluciones de llamada de eventos de E / S que ya están en la cola de eventos. Use process.nextTick
para poner en cola la función en la cabecera de la cola de eventos, de manera que se ejecute inmediatamente después de que se complete la función actual.
Por lo tanto, en el caso de que esté intentando dividir un trabajo de larga duración, vinculado a la CPU mediante la recursión, ahora querría usar setImmediate
lugar de process.nextTick
setImmediate
en la siguiente iteración, de lo contrario, cualquier devolución de llamadas de eventos de E / S no t tener la oportunidad de correr entre iteraciones.