nextTick vs set Explicación visual inmediata

90

Estoy muy confundido acerca de las diferencias entre nextTick y setImmediate. He leído toda la documentación sobre ellos en Internet pero todavía no entiendo cómo funcionan.

Ejemplos:

function log(n) { console.log(n); }

setImmediate

setImmediate(function() {
  setImmediate(function() {
    log(1);
    setImmediate(function() { log(2); });
    setImmediate(function() { log(3); });
  });
  setImmediate(function() {
    log(4);
    setImmediate(function() { log(5); });
    setImmediate(function() { log(6); });
  });
});

//1 2 3 4 5 6

nextTick

process.nextTick(function() {
  process.nextTick(function() {
    log(1);
    process.nextTick(function() { log(2); });
    process.nextTick(function() { log(3); });
  });
  process.nextTick(function() {
    log(4);
    process.nextTick(function() { log(5); });
    process.nextTick(function() { log(6); });
  });
});

//1 4 2 3 5 6

¿Por qué estos resultados? Explique con una explicación visual o muy fácil de seguir. Incluso los desarrolladores del núcleo del nodo no están de acuerdo en cómo las personas deben entender nextTick y setImmediate.

Fuentes:

Gabriel Llamas
fuente
8
Gran pregunta. Esta es una excelente manera de ilustrar las diferencias.
SystemParadox
8
El resultado es el mismo ( 1 4 2 3 5 6) para ambas ejecuciones (Nodo v5.6.0)
Deniz Ozger
¡Pregunta sabia y de ayuda!
Mehdi Raash
ambos producen la misma salida
MechaCode
1
¡Mira el año, hace 5 años! Muchas cosas podrían haber cambiado.
Gabriel Llamas

Respuestas:

105

Considere los siguientes dos ejemplos:

setImmediate

setImmediate(function A() {
  setImmediate(function B() {
    log(1);
    setImmediate(function D() { log(2); });
    setImmediate(function E() { log(3); });
  });
  setImmediate(function C() {
    log(4);
    setImmediate(function F() { log(5); });
    setImmediate(function G() { log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

// 'TIMEOUT FIRED' 1 4 2 3 5 6
// OR
// 1 'TIMEOUT FIRED' 4 2 3 5 6

nextTick

process.nextTick(function A() {
  process.nextTick(function B() {
    log(1);
    process.nextTick(function D() { log(2); });
    process.nextTick(function E() { log(3); });
  });
  process.nextTick(function C() {
    log(4);
    process.nextTick(function F() { log(5); });
    process.nextTick(function G() { log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

// 1 4 2 3 5 6 'TIMEOUT FIRED'

Las devoluciones de llamada setImmediate se disparan desde el bucle de eventos, una vez por iteración en el orden en que se pusieron en cola. Entonces, en la primera iteración del bucle de eventos, se activa la devolución de llamada A. Luego, en la segunda iteración del bucle de eventos, se dispara la devolución de llamada B, luego, en la tercera iteración del bucle de eventos, se dispara la devolución de llamada C, etc. Esto evita que el bucle de eventos se bloquee y permite que se realicen otras E / S o devoluciones de llamada del temporizador. llamado en el tiempo medio (como es el caso del tiempo de espera de 0ms, que se activa en la primera o segunda iteración del ciclo).

Las devoluciones de llamada de nextTick, sin embargo, siempre se disparan inmediatamente después de que el código actual termine de ejecutarse y ANTES de volver al bucle de eventos. En el ejemplo de nextTick, terminamos ejecutando todas las devoluciones de llamada de nextTick antes de volver al bucle de eventos. Dado que la devolución de llamada de setTimeout se llamará desde el bucle de eventos, el texto 'TIMEOUT FIRED' no se emitirá hasta que terminemos con cada devolución de llamada nextTick.

Dave Stibrany
fuente
8
Perfecto, el último párrafo es la clave para entender la principal diferencia.
Gabriel Llamas
su ejemplo de nextTick tiene una salida diferente:TIMEOUT FIRED 1 4 2 3 5 6
Jürgen Paul
¿Qué versión de nodo está ejecutando? En el nodo 0.10.x, siempre debe ejecutar sus devoluciones de llamada nextTick antes de llegar al bucle de eventos.
Dave Stibrany
23
Ojalá hubieran elegido un nombre diferente. En este momento, "nextTick" es más inmediato que setImmediate.
skerit
1
@StrugglingCoder Porque cuando A se ejecuta, establece que B y C se programen a continuación. Cuando B se ejecuta, establece que D y E se programen a continuación, pero C ya se programó para después de B. Recuerde que hay una diferencia entre cuándo se programa o se registra la devolución de llamada y cuándo se activa la devolución de llamada.
Dave Stibrany
25

De acuerdo con el documento de Node.js, los nombres de estas dos funciones se intercambian exactamente

setImmediate () ( MEJOR RECOMENDADO )

Es el fuego primero en la cola de eventos


process.nextTick () ( USAR PARA CASOS ESPECIALES, ver ejemplo más adelante )

Se dispara de inmediato, es como escribir una declaración más al final del archivo actual


Si tenemos este código

setTimeout(function(){
  console.log('Hello world 5'); // It's waiting like a normal person at a queue
}, 0);

setImmediate(function(){
  console.log('Hello world 4'); 
  // It's like get to last and be take care of first 
  // but always after of .nextTick and before of setInterval(, 0)
});

process.nextTick(function(){
   console.log('Hello world 3'); // It's like be at the bottom at this file
});

console.log('Hello world 1');
console.log('Hello world 2');

Una explicación visual según su solicitud:

ingrese la descripción de la imagen aquí

Casos de uso process.nextTick () cuando tienes que emitir un evento antes de manejarlo:

const EventEmitter = require('events');
const util = require('util');

function MyEmitter() {
  EventEmitter.call(this);

  // use nextTick to emit the event once a handler is assigned
  process.nextTick(function () {
    this.emit('event');
  }.bind(this));
}
util.inherits(MyEmitter, EventEmitter);

const myEmitter = new MyEmitter();
myEmitter.on('event', function() {
  console.log('an event occurred!');
});

Mire este video donde Philip Roberts nos da una gran explicación sobre el bucle de eventos en tiempo de ejecución y mire este depurador de eventos en línea Pruebe en vivo cómo funciona el bucle de eventos

Fuente: https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate

gsalgadotoledo
fuente
1
¡Esta respuesta tiene más sentido! Gracias @gsalgadotoledo: p man, fue aún más difícil escribir tu nombre que entender nextTick y setImmediate.
Aimal Khan
8

No puedo reproducir tus resultados para setImmediate. Debería ser lo mismo que nextTick(y está en mis pruebas) ya que en esta situación hacen prácticamente lo mismo. La única explicación razonable para eso es que de setImmediatealguna manera es sincrónico, pero no lo es.

Y de acuerdo con la documentación de NodeJS, la única diferencia real es que varios nextTickpueden dispararse en una iteración de bucle (dependiendo de maxTickDepth), mientras que se setImmediatedispara una vez por iteración.

monstruoso
fuente
3

A continuación, obtendrá una mayor claridad.

setImmediate

  1. Ejecuta un script una vez que se completa la fase de encuesta actual.
  2. Es una función de módulo temporizador y las funciones del temporizador son globales, puede llamarlas sin ellas require.
  3. Se puede borrar con clearImmediate ().
  4. Establezca la ejecución "inmediata" de la devolución de llamada después de las devoluciones de llamada de los eventos de E / S antes de setTimeout () y setInterval ().

nextTick

  1. Es una función de objeto global de proceso de NodeJS.
  2. Todas las devoluciones de llamada pasadas a process.nextTick () se resolverán antes de que continúe el bucle de eventos.
  3. Permita que los usuarios manejen los errores.
  4. Ayuda a intentar la solicitud nuevamente antes de que continúe el ciclo de eventos.

Fragmento de código simple.

console.log("I'm First");

setImmediate(function () {
  console.log('Im setImmediate');
});

console.log("I'm Second");

process.nextTick(function () {
  console.log('Im nextTick');
});

console.log("I'm Last");

/*
Output
$ node server.js
I'm First
I'm Second
I'm Last
Im nextTick
Im setImmediate
*/
Venkat.R
fuente
2

Creo que todas las respuestas anteriores son obsoletas, porque obtuve diferentes respuestas constantemente con la versión actual de nodejs y es fácil razonar sobre

var log=console.log
log(process.version)

var makeAsyncCall
if(false)
    makeAsyncCall=setImmediate
else
    makeAsyncCall=process.nextTick;

makeAsyncCall(function A () {
    makeAsyncCall(function B() {
        log(1);
        makeAsyncCall(function C() { log(2); });
        makeAsyncCall(function D() { log(3); });
    });
    makeAsyncCall(function E() {
        log(4);
        makeAsyncCall(function F() { log(5); });
        makeAsyncCall(function G() { log(6); });
    });
});
//1
//4
//2
//3
//5
//6
//in both case

Después de leer https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate deje que el uso comience desde setImmediatedebemos realizar un seguimiento de el check queueya que es donde el setImmediatereside devolución de llamada.

Primera iteración

A es empujar a check queue

cola de comprobación: [A]

Segunda iteración

Ase saca queuepara ejecutar

Durante su ejecución, puso By Eto queuey luego, Acompletó e inició la siguiente iteración

cola de comprobación: [B, E]

Tercera iteración

sacar By empujarC D

cola de comprobación: [E, C, D]

Cuarta iteración

sacar Ey empujarF G

cola de comprobación: [C, D, F, G]

Finalmente

ejecutar las devoluciones de llamada en la cola secuencialmente

Por nextTickcaso, la cola funciona exactamente de la misma manera, por eso produce el mismo resultado

Lo diferente es que:

el nextTickQueue se procesará después de que se complete la operación actual, independientemente de la fase actual del bucle de eventos

Para ser claros, el bucle de eventos mantiene múltiples colas y check queuees solo una de ellas, el nodo decidirá qué cola usar en función de algunas reglas

con process.nextTicksin embargo, es una especie de pasar por toda la normativa y ejecutar la devolución de llamada de nextTickforma inmediata

Guichi
fuente