NodeJS - setTimeout (fn, 0) vs setImmediate (fn)


Antworten:


70

setTimeout ist einfach wie das Aufrufen der Funktion nach Beendigung der Verzögerung. Wenn eine Funktion aufgerufen wird, wird sie nicht sofort ausgeführt, sondern in die Warteschlange gestellt, sodass sie ausgeführt wird, nachdem alle ausführenden und aktuell in die Warteschlange gestellten Eventhandler zuerst beendet wurden. setTimeout (, 0) bedeutet im Wesentlichen die Ausführung, nachdem alle aktuellen Funktionen in der aktuellen Warteschlange ausgeführt wurden. Es kann nicht garantiert werden, wie lange es dauern könnte.

setImmediate ist in dieser Hinsicht ähnlich, außer dass es keine Funktionswarteschlange verwendet. Es überprüft die Warteschlange der E / A-Ereignishandler. Wenn alle E / A-Ereignisse im aktuellen Snapshot verarbeitet werden, wird der Rückruf ausgeführt. Sie werden unmittelbar nach dem letzten E / A-Handler in die Warteschlange gestellt, ähnlich wie process.nextTick. Es geht also schneller.

Außerdem (setTimeout, 0) ist langsam, da der Timer vor der Ausführung mindestens einmal überprüft wird. Manchmal kann es doppelt so langsam sein. Hier ist ein Benchmark.

var Suite = require('benchmark').Suite
var fs = require('fs')

var suite = new Suite

suite.add('deffered.resolve()', function(deferred) {
  deferred.resolve()
}, {defer: true})

suite.add('setImmediate()', function(deferred) {
  setImmediate(function() {
    deferred.resolve()
  })
}, {defer: true})

suite.add('setTimeout(,0)', function(deferred) {
  setTimeout(function() {
    deferred.resolve()
  },0)
}, {defer: true})

suite
.on('cycle', function(event) {
  console.log(String(event.target));
})
.on('complete', function() {
  console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run({async: true})

Ausgabe

deffered.resolve() x 993 ops/sec ±0.67% (22 runs sampled)
setImmediate() x 914 ops/sec ±2.48% (57 runs sampled)
setTimeout(,0) x 445 ops/sec ±2.79% (82 runs sampled)

Zunächst gibt man eine Vorstellung von schnellstmöglichen Anrufen. Sie können selbst überprüfen, ob setTimeout halb so oft aufgerufen wird wie andere. Denken Sie auch daran, dass setImmediate sich an Ihre Dateisystemaufrufe anpasst. Unter Last ist die Leistung also geringer. Ich denke nicht, dass setTimeout es besser machen kann.

setTimeout ist eine unaufdringliche Methode, um Funktionen nach einiger Zeit aufzurufen. Es ist genau wie im Browser. Es ist möglicherweise nicht für die Serverseite geeignet (denken Sie daran, warum ich Benchmark.js verwendet habe, nicht setTimeout).


3
Es ist wichtig zu beachten, dass setTimeout bei fünfmaliger Verschachtelung einer erzwungenen Verzögerung von mindestens vier Millisekunden unterliegt. siehe HTML-Spezifikation
Jack Allan

Diese Quelle (aus der anderen Antwort) scheint einige der Aussagen hier zu widerlegen: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev

16

Ein großartiger Artikel über die Funktionsweise der Ereignisschleife und die Beseitigung einiger Missverständnisse. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Zitieren des Artikels:

setImmediateRückrufe werden aufgerufen, nachdem Rückrufe in der E / A-Warteschlange beendet wurden oder eine Zeitüberschreitung aufgetreten ist. setImmediate-Rückrufe werden in die Check Queue gestellt, die nach der E / A-Warteschlange verarbeitet werden.

setTimeout(fn, 0)Rückrufe werden in die Timer-Warteschlange gestellt und nach E / A-Rückrufen sowie Rückrufen in der Warteschlange überprüft. Verarbeiten Sie als Ereignisschleife die Timer-Warteschlange zuerst in jeder Iteration. Welche zuerst ausgeführt wird, hängt davon ab, um welche Phasenereignisschleife es sich handelt.


Die setTimeout-Warteschlange wird vor E / A-Rückrufen verarbeitet. ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
human

6

Mit setImmediate () wird die sofortige Ausführung des Rückrufs nach Rückrufen von E / A-Ereignissen sowie vor setTimeout und setInterval geplant.

Mit setTimeout () wird die Ausführung eines einmaligen Rückrufs nach einer Verzögerung von Millisekunden geplant.

Das sagen die Dokumente.

setTimeout(function() {
  console.log('setTimeout')
}, 0)

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

Wenn Sie den obigen Code ausführen, sieht das Ergebnis folgendermaßen aus ... obwohl im aktuellen Dokument angegeben ist, dass "die" sofortige "Ausführung des Rückrufs nach Rückrufen von E / A-Ereignissen und vor setTimeout und setInterval geplant werden soll". ..

Ergebnis..

setTimeout

setImmediate

Wenn Sie Ihr Beispiel in einen anderen Timer einbinden, wird immer setImmediate gefolgt von setTimeout gedruckt.

setTimeout(function() {
  setTimeout(function() {
    console.log('setTimeout')
  }, 0);
  setImmediate(function() {
    console.log('setImmediate')
  });
}, 10);

Wann bevorzugen Sie einen gegenüber dem anderen?
Shlomi Schwartz

21
Sie haben nicht erklärt, warum das, was Sie gezeigt haben, passiert. Diese Antwort war für mich nicht nützlich.
Clint Eastwood

3
@ Savannah In Ihrem ersten Ergebnis erklären Sie bitte, warum setTimeout zuerst ausgeführt wurde, bevor setImmediate
Agus Syahputra

2
@AgusSyahputra Überprüfen Sie dies heraus: github.com/nodejs/node-v0.x-archive/issues/25788
Rodrigo Branas

1
SetImmediate wird nicht immer vor setTimeout und setInterval ausgeführt
Mithun GS

2

Verwenden setImmediateSie immer , es sei denn, Sie sind sich wirklich sicher, dass Sie brauchen setTimeout(,0)(aber ich kann mir nicht einmal vorstellen, wofür). setImmediateRückruf wird fast immer vorher ausgeführt setTimeout(,0), außer wenn er im ersten Tick und im setImmediateRückruf aufgerufen wird .


1
Ich würde sagen, der Hauptgrund für die Verwendung von setTimeout anstelle von setImmediate ist, dass Ihr Code von Browsern ausgeführt werden muss, in denen setImmediate nicht implementiert ist. Selbst dann können Sie einfach eine Unterlegscheibe erstellen.
Gregory Magarshak

9
Dies ist ein unsolider Rat. Wenn alles zuerst gefragt wird, werden die aufkommenden Leistungsmerkmale der asynchronen Ausführung im Vergleich zum Anstehen am Ende Junk sein. setTimeoutsollte die Anlaufstelle sein, mit setImmediatenur verwendet, wenn gezeigt wird, dass es notwendig ist.
Rich Remer

1

Völlig unzufrieden mit den gelieferten Antworten. Ich habe hier eine meiner Meinung nach bessere Antwort veröffentlicht: https://stackoverflow.com/a/56724489/5992714

Fragen ist ein mögliches Duplikat von Warum ist das Verhalten von setTimeout (0) und setImmediate () bei Verwendung im Hauptmodul undefiniert?


1
Bitte posten Sie nicht genau die gleiche Antwort auf zwei Fragen. Wenn die Fragen unterschiedlich sind, passen Sie die Antwort an jede an. Wenn sie gleich sind, markieren oder stimmen Sie ab, um eine Kopie als Duplikat zu schließen.
Tom Zych

@ TomZych notiert.
Mensch

0

Ich denke, die Antwort von Navya S ist nicht richtig, hier ist mein Testcode:

let set = new Set();

function orderTest() {
  let seq = [];
  let add = () => set.add(seq.join());
  setTimeout(function () {
    setTimeout(function () {
      seq.push('setTimeout');
      if (seq.length === 2) add();
    }, 0);

    setImmediate(function () {
      seq.push('setImmediate');
      if (seq.length === 2) add();
    });
  }, 10);
}

// loop 100 times
for (let i = 0; i < 100; i++) {
  orderTest();
}

setTimeout(() => {
  // will print one or two items, it's random
  for (item of set) {
    console.log(item);
  }
}, 100);

Die Erklärungen finden Sie hier


0

setTimeout (fn, 0) kann verwendet werden, um zu verhindern, dass der Browser bei massiven Updates einfriert. In websocket.onmessage können sich beispielsweise HTML-Änderungen ergeben. Wenn weiterhin Nachrichten eingehen, friert der Browser möglicherweise ein, wenn setImmidiate verwendet wird


0

Um sie genau zu verstehen, gehen Sie bitte einmal die Phasen der Ereignisschleife durch.

SetImmediate: Wird in der "Check" -Phase ausgeführt. Die Kontrollphase wird nach der I / O - Phase genannt.

SetTimeOut: Wird in der "Timer" -Phase ausgeführt. Die Timer - Phase ist die erste Phase , aber nach der genannten E / A - Phase sowie die Preisphase.

Um die Ausgabe deterministisch zu erhalten, hängt es davon ab, in welcher Phase sich die Ereignisschleife befindet. Dementsprechend können wir die Funktion aus zwei verwenden.


-4

Verwenden Sie setImmediate (), um die Ereignisschleife nicht zu blockieren. Der Rückruf wird in der nächsten Ereignisschleife ausgeführt, sobald die aktuelle abgeschlossen ist.

Verwenden Sie setTimeout () für kontrollierte Verzögerungen. Die Funktion wird nach der angegebenen Verzögerung ausgeführt. Die minimale Verzögerung beträgt 1 Millisekunde.

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.