nextTick vs setImmediate, visuelle Erklärung


88

Ich bin sehr verwirrt über die Unterschiede zwischen nextTick und setImmediate. Ich habe die gesamte Dokumentation über sie im Internet gelesen, verstehe aber immer noch nicht, wie sie funktionieren.

Beispiele:

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

Warum diese Ergebnisse? Bitte erklären Sie mit einer visuellen oder sehr leicht verständlichen Erklärung. Selbst die Entwickler des Knotenkerns sind sich nicht einig, wie nextTick und setImmediate von Menschen verstanden werden sollen.

Quellen:


8
Gute Frage. Dies ist eine hervorragende Möglichkeit, die Unterschiede zu veranschaulichen.
SystemParadox

8
Die Ausgabe ist 1 4 2 3 5 6für beide Ausführungen gleich ( ) (Node v5.6.0)
Deniz Ozger

Kluge und helfende Frage!
Mehdi Raash

beide produzieren die gleiche Ausgabe
MechaCode

Schauen Sie sich das Jahr vor 5 Jahren an! Vieles hätte sich ändern können.
Gabriel Llamas

Antworten:


104

Betrachten Sie die folgenden zwei Beispiele:

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'

setImmediate-Rückrufe werden einmal pro Iteration in der Reihenfolge, in der sie in die Warteschlange gestellt wurden, aus der Ereignisschleife ausgelöst. Bei der ersten Iteration der Ereignisschleife wird also Rückruf A ausgelöst. Bei der zweiten Iteration der Ereignisschleife wird dann Rückruf B ausgelöst, dann wird bei der dritten Iteration der Ereignisschleife Rückruf C ausgelöst usw. Dies verhindert, dass die Ereignisschleife blockiert wird, und ermöglicht, dass andere E / A- oder Timer-Rückrufe ausgeführt werden wird in der mittleren Zeit aufgerufen (wie im Fall des 0-ms-Timeouts, das bei der Iteration der 1. oder 2. Schleife ausgelöst wird).

nextTick-Rückrufe werden jedoch immer sofort ausgelöst, nachdem der aktuelle Code ausgeführt wurde und bevor Sie zur Ereignisschleife zurückkehren. Im nextTick-Beispiel führen wir am Ende alle nextTick-Rückrufe aus, bevor wir jemals zur Ereignisschleife zurückkehren. Da der Rückruf von setTimeout von der Ereignisschleife aufgerufen wird, wird der Text 'TIMEOUT FIRED' erst ausgegeben, wenn wir mit jedem nextTick-Rückruf fertig sind.


8
Perfekt, der letzte Absatz ist der Schlüssel zum Verständnis des Hauptunterschieds.
Gabriel Llamas

Ihr nextTick-Beispiel hat eine andere Ausgabe:TIMEOUT FIRED 1 4 2 3 5 6
Jürgen Paul

Welche Version des Knotens verwenden Sie? Auf Knoten 0.10.x sollten Ihre nextTick-Rückrufe immer ausgeführt werden, bevor Sie die Ereignisschleife erreichen.
Dave Stibrany

23
Ich wünschte, sie hätten einen anderen Namen gewählt. Im Moment ist "nextTick" unmittelbarer als setImmediate.
Skerit

1
@StrugglingCoder Denn wenn A ausgeführt wird, werden B und C so festgelegt, dass sie als nächstes geplant werden. Wenn B ausgeführt wird, werden D und E als nächstes geplant, aber C wurde bereits nach B geplant. Beachten Sie, dass es einen Unterschied zwischen dem geplanten oder registrierten Rückruf und dem tatsächlichen Auslösen des Rückrufs gibt.
Dave Stibrany

24

Laut Node.js werden die Dokumentnamen dieser beiden Funktionen genau vertauscht

setImmediate () ( BEST EMPFOHLEN )

Es ist Feuer zuerst in der Ereigniswarteschlange


process.nextTick () ( VERWENDUNG FÜR SPEZIELLE FÄLLE siehe Beispiel später )

Es ist sofort Feuer, es ist eine Art Erklärung mehr am Ende in der aktuellen Datei


Wenn wir diesen Code haben

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');

Eine visuelle Erklärung gemäß Ihrer Anfrage:

Geben Sie hier die Bildbeschreibung ein

Fälle für die Verwendung von process.nextTick (), wenn Sie zuvor ein Ereignis ausgeben müssen, um es zu behandeln:

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!');
});

Schauen Sie sich dieses Video an, in dem Philip Roberts uns eine großartige Erklärung zur Laufzeit-Ereignisschleife gibt, und schauen Sie sich diesen Online-Eventloop-Debugger an Live-Test, wie die Ereignisschleife funktioniert

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


1
Diese Antwort macht mehr Sinn! Danke @gsalgadotoledo: p Mann, es war noch schwieriger, deinen Namen zu schreiben, als nextTick und setImmediate zu verstehen.
Aimal Khan

8

Ich kann Ihre Ergebnisse für nicht reproduzieren setImmediate. Es sollte dasselbe sein wie nextTick(und es ist in meinen Tests), da sie in dieser Situation so ziemlich dasselbe tun. Die einzig vernünftige Erklärung dafür ist diesetImmediate es irgendwie synchron ist, aber nicht.

Und laut NodeJS-Dokumentation besteht der einzige wirkliche Unterschied darin, dass mehrere nextTickin einer Schleifeniteration ausgelöst werden können (abhängig von maxTickDepth), während sie setImmediateeinmal pro Iteration ausgelöst werden.


3

Unten erhalten Sie eine bessere Klarheit.

setImmediate

  1. Sobald die aktuelle Abfragephase abgeschlossen ist, wird ein Skript ausgeführt.
  2. Es ist eine Timer-Modul-Funktion und Timer-Funktionen sind global, Sie können sie auch ohne aufrufen require.
  3. Es kann mit clearImmediate () gelöscht werden.
  4. Legen Sie die "sofortige" Ausführung des Rückrufs nach den Rückrufen von E / A-Ereignissen vor setTimeout () und setInterval () fest.

nextTick

  1. Es ist eine globale Prozessobjektfunktion von NodeJS.
  2. Alle an process.nextTick () übergebenen Rückrufe werden aufgelöst, bevor die Ereignisschleife fortgesetzt wird.
  3. Ermöglichen Sie Benutzern, Fehler zu behandeln.
  4. Hilft, die Anforderung erneut zu versuchen, bevor die Ereignisschleife fortgesetzt wird.

Einfaches Code-Snippet.

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
*/

2

Ich denke, alle oben genannten Antworten sind veraltet, da ich mit der aktuellen Version von nodejs ständig unterschiedliche Antworten erhalten habe und es leicht zu überlegen ist

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

Nach dem Lesen von https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate beginnen setImmediatewir mit der Verwendung das, check queueweil es dort ist, wo dassetImmediate Rückruf befindet.

Erste Iteration

A ist zu drücken check queue

Warteschlange prüfen: [A]

Zweite Iteration

A wird herausgezogen queue um auszuführen

Während seiner Ausführung legte es Bund Ezu queueund dann,A vollständig und nächste Iteration beginnen

Warteschlange prüfen: [B, E]

Dritte Iteration

herausziehen Bund drückenC D

Warteschlange prüfen: [E, C, D]

Vierte Iteration

herausziehen Eund drückenF G

Warteschlange prüfen: [C, D, F, G]

Schließlich

Führen Sie die Rückrufe in der Warteschlange nacheinander aus

In diesem nextTickFall funktioniert die Warteschlange genauso, weshalb sie das gleiche Ergebnis liefert

Der Unterschied ist:

Die nextTickQueue wird nach Abschluss der aktuellen Operation unabhängig von der aktuellen Phase der Ereignisschleife verarbeitet

Um klar zu sein, verwaltet die Ereignisschleife mehrere Warteschlangen und check queue ist nur eine davon. Der Knoten entscheidet anhand einiger Regeln, welche Warteschlange verwendet werden soll

Dabei wird process.nextTickjedoch die gesamte Regel umgangen und der Rückruf nextTicksofort ausgeführt

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.