Heim > Web-Frontend > js-Tutorial > Eine kurze Diskussion über Timer in Node.js_node.js

Eine kurze Diskussion über Timer in Node.js_node.js

WBOY
Freigeben: 2016-05-16 15:54:04
Original
1355 Leute haben es durchsucht

Implementierung des Timers in Node.js

Wie im vorherigen Blogbeitrag erwähnt, wird der Timer in Node nicht durch das Öffnen eines neuen Threads implementiert, sondern direkt in der Ereignisschleife. Im Folgenden werden mehrere JavaScript-Timer-Beispiele und Node-bezogener Quellcode verwendet, um zu analysieren, wie die Timer-Funktion in Node implementiert wird.

Funktionen der Timer-Funktion in JavaScript

Ob es sich um Node oder den Browser handelt, es gibt zwei Timer-Funktionen, setTimeout und setInterval, und ihre Arbeitseigenschaften sind grundsätzlich gleich, daher wird im Folgenden nur Node als Beispiel für die Analyse verwendet.

Wir wissen, dass sich der Timer in JavaScript nicht vom zugrunde liegenden geplanten Interrupt des Computers unterscheidet. Wenn ein Interrupt eintrifft, wird der aktuell ausgeführte Code unterbrochen und an die geplante Interrupt-Verarbeitungsfunktion übergeben. Wenn der JavaScript-Timer abläuft und im aktuellen Ausführungsthread kein Code ausgeführt wird, wird die entsprechende Rückruffunktion ausgeführt. Wenn derzeit Code ausgeführt wird, unterbricht die JavaScript-Engine weder den aktuellen Code, um den Rückruf auszuführen start Der neue Thread führt den Rückruf aus, wird jedoch verarbeitet, nachdem der aktuelle Code ausgeführt wurde.

console.time('A')
setTimeout(function () {
  console.timeEnd('A');
}, 100);
var i = 0;
for (; i < 100000; i++) { }
Nach dem Login kopieren

Wenn Sie den obigen Code ausführen, können Sie sehen, dass die endgültige Ausgabezeit nicht etwa 100 ms, sondern einige Sekunden beträgt. Dies zeigt, dass die geplante Callback-Funktion tatsächlich nicht ausgeführt wird, bevor die Schleife abgeschlossen ist, sondern bis zum Ende der Schleife verschoben wird. Tatsächlich können während der Ausführung von JavaScript-Code nicht alle Ereignisse verarbeitet werden, und neue Ereignisse müssen verarbeitet werden, bis der aktuelle Code abgeschlossen ist. Aus diesem Grund reagiert der Browser nicht mehr, wenn darin zeitaufwändiger JavaScript-Code ausgeführt wird. Um mit dieser Situation umzugehen, können wir die Yielding Processes-Technik verwenden, um den zeitaufwändigen Code in kleine Blöcke (Chunks) aufzuteilen, nach der Verarbeitung jedes Blocks einmal setTimeout auszuführen und nach einer kurzen Zeitspanne zuzustimmen, den nächsten Block zu verarbeiten Während dieser Zeit kann der Browser/Knoten in der Leerlaufzeit Ereignisse in der Warteschlange verarbeiten.

Ergänzende Informationen

Erweiterte Timer und Yielding-Prozesse werden ausführlicher in Kapitel 22 „Fortgeschrittene Techniken der fortgeschrittenen JavaScript-Programmierung“, dritte Ausgabe, besprochen.

Timer-Implementierung im Knoten

libuvs Initialisierung des Typs uv_loop_t

Im vorherigen Blog-Beitrag wurde erwähnt, dass Node die uv_run-Funktion von libuv aufruft, um default_loop_ptr für die Ereignisplanung zu starten. default_loop_ptr verweist auf eine Variable default_loop_struct vom Typ uv_loop_t. Wenn der Knoten startet, ruft er uv_loop_init(&default_loop_struct) auf, um ihn zu initialisieren. Der Auszug der Funktion uv_loop_init lautet wie folgt:

int uv_loop_init(uv_loop_t* loop) {
 ...
 loop->time = 0;
 uv_update_time(loop);
 ...
}
Nach dem Login kopieren

Sie können sehen, dass dem Zeitfeld der Schleife zuerst der Wert 0 zugewiesen wird und dann die Funktion uv_update_time aufgerufen wird, die loop.time die neueste Zählzeit zuweist.

Nach Abschluss der Initialisierung hat default_loop_struct.time einen Anfangswert und zeitbezogene Vorgänge werden mit diesem Wert verglichen, um zu bestimmen, ob die entsprechende Rückruffunktion aufgerufen werden soll.

libuvs Ereignisplanungskern

Wie bereits erwähnt, ist die Funktion uv_run der Kernbestandteil der libuv-Bibliothek zur Implementierung der Ereignisschleife. Das Folgende ist ihr Flussdiagramm:

Hier ist eine kurze Beschreibung der obigen Logik im Zusammenhang mit dem Timer:

Aktualisieren Sie das Zeitfeld der aktuellen Schleife, das das „Jetzt“ unter dem aktuellen Schleifenkonzept markiert

Überprüfen Sie, ob die Schleife aktiv ist, d. h., ob es irgendwelche Aufgaben (Handler/Anfragen) gibt, die in der Schleife verarbeitet werden müssen. Wenn nicht, besteht keine Notwendigkeit, eine Schleife durchzuführen Überprüfen Sie die registrierten Timer. Wenn die in einem Timer angegebene Zeit hinter der aktuellen Zeit zurückbleibt, bedeutet dies, dass der Timer abgelaufen ist und die entsprechende Rückruffunktion ausgeführt wird Führen Sie eine E/A-Abfrage durch (d. h. blockieren Sie den Thread und warten Sie, bis das E/A-Ereignis eintritt, wenn der nächste Timer abläuft). Hören Sie auf zu warten und führen Sie den Rückruf des nächsten Timers aus.



Wenn ein I/O-Ereignis auftritt, wird der entsprechende Rückruf ausgeführt. Da während der Rückrufausführungszeit möglicherweise ein anderer Timer abgelaufen ist, muss der Timer erneut überprüft und der Rückruf ausgeführt werden.
(Eigentlich ist (4.) hier komplizierter und nicht nur ein einstufiger Vorgang. Diese Beschreibung dient nur dazu, keine weiteren Details einzubeziehen und sich auf die Implementierung des Timers zu konzentrieren.)

Der Knoten ruft uv_run so lange auf, bis die Schleife nicht mehr aktiv ist.



timer_wrap und Timer im Knoten

Es gibt eine TimerWrap-Klasse in Node, die als timer_wrap-Modul in Node registriert ist.

NODE_MODULE_CONTEXT_AWARE_BUILTIN(timer_wrap, node::TimerWrap::Initialize)

Die TimerWrap-Klasse ist im Grunde eine direkte Kapselung von uv_timer_t, und NODE_MODULE_CONTEXT_AWARE_BUILTIN ist ein Makro, das von Node zum Registrieren integrierter Module verwendet wird.

Nach diesem Schritt kann JavaScript dieses Modul abrufen und bedienen. Die Datei src/lib/timers.js verwendet JavaScript, um die Funktion timer_wrap zu kapseln und exportiert exports.setTimeout, exports.setInterval, exports.setImmediate und andere Funktionen.

Knotenstart und globale Initialisierung

Im vorherigen Artikel wurde erwähnt, dass Node beim Start die Ausführungsumgebung LoadEnvironment(env) lädt. Ein sehr wichtiger Schritt in dieser Funktion ist das Laden von src/node.js und das Laden der angegebenen Modul Und global und Prozess initialisieren. Natürlich werden auch Funktionen wie setTimeout über src/node.js an das globale Objekt gebunden.

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er gefällt Ihnen allen.

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage