Wie funktioniert setTimeout in Node.JS?

111

Ich denke, wenn es einmal ausgeführt wurde, befindet es sich in der Warteschlange, aber gibt es in der Warteschlange eine Gewissheit, dass es genau nach X Millisekunden aufgerufen wird? Oder verzögern andere schwere Aufgaben in der Warteschlange dies?

MyCodeGone
quelle
14
Kein Nicht-Echtzeit-Betriebssystem wird jemals eine Garantie für ernsthafte Genauigkeit ermöglichen. Alle möglichen Dinge im System können (und werden) dem Timer-Mechanismus im Wege stehen.
Pointy

Antworten:

174

Die Semantik von setTimeout ist ungefähr dieselbe wie in einem Webbrowser: Das Timeout-Argument ist ein Minimum von ms, die vor der Ausführung gewartet werden muss, keine Garantie. Wenn Sie 0, eine Nicht-Zahl oder eine negative Zahl übergeben, wird eine Mindestanzahl von ms gewartet. In Node ist dies 1 ms, in Browsern können es bis zu 50 ms sein.

Der Grund dafür ist, dass JavaScript nicht durch JavaScript vorweggenommen wird. Betrachten Sie dieses Beispiel:

setTimeout(function () {
  console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')

Der Fluss hier ist:

  1. Planen Sie das Timeout für 100 ms.
  2. beschäftigt warten für 5000ms.
  3. Rückkehr zur Ereignisschleife. Suchen Sie nach ausstehenden Timern und führen Sie sie aus.

Wenn dies nicht der Fall wäre, könnte ein Bit JavaScript ein anderes "unterbrechen". Wir müssten Mutexe und Semaphore und dergleichen einrichten, um zu verhindern, dass Code wie dieser extrem schwer zu überlegen ist:

var a = 100;
setTimeout(function () {
  a = 0;
}, 0);
var b = a; // 100 or 0?

Die Single-Threaded-Funktion der JavaScript-Ausführung von Node erleichtert die Arbeit mit den meisten anderen Arten der Parallelität erheblich. Der Nachteil ist natürlich, dass ein schlecht benommener Teil des Programms das Ganze mit einer Endlosschleife blockieren kann.

Ist dies ein besserer Dämon im Kampf als die Komplexität der Prävention? Kommt darauf an.

isaacs
quelle
20
Sie erhalten eine +1 für die außergewöhnlich genaue console.logNachricht.
Fund Monica Klage
Mir gefällt, wie Sie TIME in Ihrem String in Großbuchstaben geschrieben haben. Sehr gute Erklärung !!!
Alisson
43

Die Idee des Nicht-Blockierens ist, dass die Schleifeniterationen schnell sind. Das Iterieren für jeden Tick sollte also so kurz sein, dass das setTimeout auf eine angemessene Genauigkeit genau ist (um etwa <100 ms oder so).

Theoretisch hast du allerdings recht. Wenn ich eine Anwendung schreibe und das Häkchen blockiere, wird setTimeouts verzögert. Um Ihre Frage zu beantworten, wer kann sicherstellen, dass setTimeouts pünktlich ausgeführt werden? Durch das Schreiben von nicht blockierendem Code können Sie den Genauigkeitsgrad bis zu nahezu jedem angemessenen Genauigkeitsgrad steuern.

Solange Javascript in Bezug auf die Codeausführung "Single-Threaded" ist (ausgenommen Web-Worker und dergleichen), wird dies immer passieren. Die Single-Thread-Natur ist in den meisten Fällen eine enorme Vereinfachung, erfordert jedoch, dass die nicht blockierende Sprache erfolgreich ist.

Probieren Sie diesen Code entweder in Ihrem Browser oder im Knoten aus, und Sie werden feststellen, dass es keine Garantie für die Richtigkeit gibt. Im Gegenteil, das setTimeout wird sehr spät sein:

var start = Date.now();

// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);

// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}

Wenn der Interpreter die Schleife nicht optimiert (was bei Chrom nicht der Fall ist), erhalten Sie Tausende. Entfernen Sie die Schlaufe und Sie werden sehen, dass es 500 auf der Nase ist ...

David
quelle
9

Die einzige Möglichkeit, um sicherzustellen, dass Code ausgeführt wird, besteht darin, Ihre setTimeout-Logik in einem anderen Prozess zu platzieren.

Verwenden Sie das untergeordnete Prozessmodul, um ein neues Programm node.js zu erzeugen, das Ihre Logik ausführt und Daten über eine Art Stream (möglicherweise tcp) an diesen Prozess übergibt.

Selbst wenn in Ihrem Hauptprozess ein langer Blockierungscode ausgeführt wird, hat sich Ihr untergeordneter Prozess bereits selbst gestartet und ein setTimeout in einen neuen Prozess und einen neuen Thread eingefügt. Er wird daher ausgeführt, wenn Sie dies erwarten.

Weitere Komplikationen treten auf Hardwareebene auf, auf der mehr Threads als Prozesse ausgeführt werden. Daher führt die Kontextumschaltung zu (sehr geringen) Verzögerungen gegenüber dem erwarteten Timing. Dies sollte vernachlässigbar sein. Wenn es darauf ankommt, müssen Sie ernsthaft überlegen, was Sie versuchen, warum Sie eine solche Genauigkeit benötigen und welche alternative Hardware in Echtzeit verfügbar ist, um die Aufgabe zu erledigen.

Im Allgemeinen ist es für die Skalierung Ihres Codes wichtig, untergeordnete Prozesse zu verwenden und Anwendungen mit mehreren Knoten als separate Prozesse zusammen mit einem Load Balancer oder einem gemeinsam genutzten Datenspeicher (wie Redis) auszuführen.

Raynos
quelle
9

setTimeoutist eine Art Thread , der eine Operation für eine bestimmte Zeit enthält und ausführt.

setTimeout(function,time_in_mills);

hier sollte das erste Argument ein Funktionstyp sein; Wenn Sie beispielsweise Ihren Namen nach 3 Sekunden drucken möchten, sollte Ihr Code wie folgt aussehen.

setTimeout(function(){console.log('your name')},3000);

Der wichtigste Punkt, an den Sie sich erinnern sollten, ist, was immer Sie mit der setTimeoutMethode tun möchten , tun Sie es innerhalb einer Funktion . Wenn Sie eine andere Methode aufrufen möchten, indem Sie einige Parameter analysieren, sollte Ihr Code wie folgt aussehen:

setTimeout(function(){yourOtherMethod(parameter);},3000);
Ashana.Jackol
quelle
8

setTimeout(callback,t)wird verwendet, um einen Rückruf nach mindestens einer Millisekunde auszuführen . Die tatsächliche Verzögerung hängt von vielen externen Faktoren ab, wie z. B. der Granularität des Betriebssystem-Timers und der Systemlast.

Es besteht also die Möglichkeit, dass es kurz nach der eingestellten Zeit aufgerufen wird, aber nie zuvor aufgerufen wird.

Ein Timer kann nicht länger als 24,8 Tage dauern.

Siva Prakash
quelle