[Javascript] setImmediate vs. nextTick


Answers

En los comentarios en la respuesta, no establece explícitamente que nextTick cambió de Macrosemantics a Microsemantics.

antes del nodo 0.9 (cuando se introdujo setImmediate), nextTick funcionaba al comienzo 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

echa un vistazo a https://github.com/YuzuJS/setImmediate para obtener herramientas y detalles

Question

La versión 0.10 de Node.js fue lanzada hoy e introdujo setImmediate . La documentación de cambios de API sugiere usarlo cuando se realizan llamadas recursivas nextTick .

De lo que dice MDN , parece muy similar a process.nextTick .

¿Cuándo debería usar nextTick y cuándo debo usar setImmediate ?




Creo que puedo ilustrar esto bastante bien. Como se llama a nextTick al final de la operación actual, al llamarlo recursivamente puede terminar bloqueando el bucle de evento para continuar. setImmediate resuelve esto setImmediate en la fase de verificación del bucle de evento, permitiendo que el bucle de evento continúe normalmente.

   ┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘

fuente: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

Tenga en cuenta que la fase de verificación es inmediatamente posterior a la fase de votación. Esto se debe a que la fase de sondeo y las devoluciones de llamada de E / S son los lugares más probables donde se ejecutarán sus llamadas a setImmediate . Entonces, idealmente, la mayoría de esas llamadas serán realmente inmediatas, pero no tan inmediatas como nextTick que se verifica después de cada operación y técnicamente existe fuera del ciclo de eventos.

Echemos un vistazo a 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 avanzando en la primera iteración del ciclo de eventos. Llamará a la función de step con iteración cero. A continuación, registrará dos controladores, uno para setImmediate y otro para process.nextTick . Luego, recursivamente llamamos a esta función 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 evento, por lo que aunque se haya registrado en segundo lugar, se ejecutará primero.

El orden termina siendo: nextTick dispara a medida que la operación actual finaliza, el siguiente ciclo de evento comienza, las fases de bucle de evento normal se ejecutan, setImmediate incendios setImmediate y llama de forma recursiva nuestra función step a step para comenzar nuevamente el proceso. La operación actual finaliza, los nextTick , etc.

El resultado 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, nextTick nuestra llamada recursiva para step a nuestro controlador nextTick lugar de al 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 nextTick cosas se comportarán en un orden diferente. Nuestra primera iteración del bucle de evento se ejecuta y llama al step registrar un controlador setImmedaite así como un controlador nextTick . Después de que la operación actual finalice, nuestro nextTick controlador de nextTick dispara el llamado de forma recursiva step a step y registra otro manejador de setImmediate así como otro manejador nextTick . Como un 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 del controlador actual. Los manejadores nextTick seguirán disparando, evitando que el bucle de evento actual continúe. Pasaremos por todos nuestros manipuladores nextTick antes de que veamos un único setImmediate handler.

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ésemos interrumpido la llamada recursiva y la nextTick abortado después de 10 iteraciones, las llamadas NextTick mantendrían la recurrencia y nunca dejarían que el bucle de eventos continuase a la siguiente fase. Así es como nextTick puede convertirse en bloqueo cuando se usa recursivamente, mientras que setImmediate se disparará en el siguiente evento y configurar otro controlador setImmediate desde dentro no interrumpirá el bucle de evento actual, lo que le permitirá continuar ejecutando las fases del bucle de evento como siempre. .

¡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 nextTick parece que va a disparar en el próximo ciclo de eventos en lugar de al final del actual, y el final del ciclo actual es más " inmediato "que el comienzo del siguiente ciclo. Oh, bueno, eso es lo que obtenemos a medida que madura la API y la gente depende de las interfaces existentes.