Skip to content

setImmediate() verstehen

Wenn du ein Codefragment asynchron, aber so schnell wie möglich ausführen möchtest, ist eine Möglichkeit die setImmediate()-Funktion, die von Node.js bereitgestellt wird:

js
setImmediate(() => {
    // tue etwas
})

Jede als Argument an setImmediate() übergebene Funktion ist ein Callback, der in der nächsten Iteration der Event-Loop ausgeführt wird.

Wie unterscheidet sich setImmediate() von setTimeout(() => {}, 0) (Übergabe eines 0ms-Timeouts) und von process.nextTick() und Promise.then()?

Eine Funktion, die an process.nextTick() übergeben wird, wird in der aktuellen Iteration der Event-Loop ausgeführt, nachdem die aktuelle Operation beendet ist. Das bedeutet, dass sie immer vor setTimeout und setImmediate ausgeführt wird.

Ein setTimeout()-Callback mit einer Verzögerung von 0 ms ist sehr ähnlich wie setImmediate(). Die Ausführungsreihenfolge hängt von verschiedenen Faktoren ab, aber beide werden in der nächsten Iteration der Event-Loop ausgeführt.

Ein process.nextTick-Callback wird zur process.nextTick-Warteschlange hinzugefügt. Ein Promise.then()-Callback wird zur Microtask-Warteschlange der Promises hinzugefügt. Ein setTimeout- oder setImmediate-Callback wird zur Macrotask-Warteschlange hinzugefügt.

Die Event-Loop führt zuerst Aufgaben in der process.nextTick-Warteschlange aus, dann die Microtask-Warteschlange der Promises und dann die setTimeout- oder setImmediate-Macrotask-Warteschlange.

Hier ist ein Beispiel, um die Reihenfolge zwischen setImmediate(), process.nextTick() und Promise.then() zu zeigen:

js
const baz = () => console.log('baz');
const foo = () => console.log('foo');
const zoo = () => console.log('zoo');
const start = () => {
  console.log('start');
  setImmediate(baz);
  new Promise((resolve, reject) => {
    resolve('bar');
  }).then(resolve => {
    console.log(resolve);
    process.nextTick(zoo);
  });
  process.nextTick(foo);
};
start();
// start foo bar zoo baz

Dieser Code ruft zuerst start() auf, dann foo() in der process.nextTick-Warteschlange. Danach wird die Microtask-Warteschlange der Promises verarbeitet, die "bar" ausgibt und gleichzeitig zoo() in der process.nextTick-Warteschlange hinzufügt. Dann wird zoo() aufgerufen, das gerade hinzugefügt wurde. Am Ende wird baz() in der Macrotask-Warteschlange aufgerufen.

Das oben genannte Prinzip gilt in CommonJS-Fällen, aber beachte, dass in ES-Modulen, z. B. mjs-Dateien, die Ausführungsreihenfolge anders ist:

js
// start bar foo zoo baz

Dies liegt daran, dass das geladene ES-Modul als asynchrone Operation verpackt wird und das gesamte Skript daher bereits in der Microtask-Warteschlange der Promises enthalten ist. Wenn also das Promise sofort aufgelöst wird, wird sein Callback an die Microtask-Warteschlange angehängt. Node.js wird versuchen, die Warteschlange zu leeren, bevor es zu einer anderen Warteschlange übergeht, und daher wird zuerst "bar" ausgegeben.