1. Öffnungsanalyse
Im vorherigen Kapitel haben wir das grundlegende theoretische Wissen von Nodejs gelernt. Das Verständnis dieses theoretischen Wissens ist entscheidend. In den folgenden Kapiteln lernen wir in den offiziellen Dokumenten nach und nach verschiedene Module. Nun, es ist Zeit für den Protagonisten dieses Artikels, auf der Bühne zu erscheinen. Global
Schauen wir uns die offizielle Definition an:
Globale Objekte Diese Objekte sind in allen Modulen verfügbar. Einige dieser Objekte sind nicht tatsächlich im globalen Bereich, sondern im Modulbereich - dies wird beachtet.
Diese Objekte sind in allen Modulen verfügbar. Tatsächlich befinden sich einige Objekte nicht im globalen Bereich, sondern in seinem Modulbereich - diese werden identifiziert.
In Browsern ist der Umfang der obersten Ebene der globale Bereich. Das bedeutet, dass in Browsern, wenn Sie sich im globalen Bereich var something eine globale Variable definiert.
Im Knoten ist dies anders. Der Umfang der obersten Ebene ist nicht der globale Bereich. var something in einem Knotenmodul ist lokal zu diesem Modul.
Ich denke, jeder sollte nicht mit dem Konzept globaler Objekte vertraut sein. Im Browser ist der globale Umfang auf höchster Ebene. Wenn Sie "var" verwenden, um eine Variable im globalen Bereich zu definieren, wird diese Variable als globaler Umfang definiert.
Aber es ist anders in NodeJs. Das höchste Umfang des Umfangs ist kein globaler Bereich. In einem Modul wird eine Variable unter Verwendung von "var" definiert, und diese Variable befindet sich nur im Bereich dieses Moduls.
In NodeJs sind Variablen, Funktionen oder in einem Modul definierte Methoden nur in diesem Modul verfügbar, können jedoch durch die Verwendung des Exportobjekts an außerhalb des Moduls übergeben werden.
In Node.js gibt es jedoch immer noch ein globales Zielfernrohr, dh Sie können Variablen, Funktionen oder Klassen definieren, für die keine Module geladen werden müssen.
Gleichzeitig werden einige globale Methoden und globale Klasse -globale Objekte im Voraus vordefiniert, was die globalen Namespaces in NodeJs sind. Alle globalen Variablen, Funktionen oder Objekte sind Attributwerte des Objekts.
In der Repl -Running -Umgebung können Sie die Details im globalen Objekt über die folgende Erklärung beobachten, siehe Abbildung unten:
Ich werde über die relevanten Attributwertobjekte sprechen, die auf dem globalen Objekt nacheinander montiert sind.
(1), Prozess
Prozess {Objekt} Das Prozessobjekt. Sehen Sie den Abschnitt "Prozessobjekt".
Prozess {Objekt} Dies ist ein Prozessobjekt. Ich werde in den folgenden Kapiteln ausführlich erklären, aber hier werde ich zuerst eine API herausnehmen, um darüber zu sprechen.
process.nextTick (Callback)
Rufen Sie auf der nächsten Schleife um die Event -Schleife diesen Rückruf an. Dies ist kein einfacher Alias für SetTimeout (FN, 0), es ist viel effizienter. Es läuft normalerweise vor einem anderen I/A -Ereignis, aber es gibt einige Ausnahmen. Siehe Prozess.Maxtickdepth unten.
Callback -Rückruffunktion in der nächsten Schleife der Ereignisschleife. Dies ist kein einfacher Alias für die Funktion SetTimeout (FN, 0), da sie viel effizienter ist.
Diese Funktion kann unsere Rückruffunktion vor jedem E/A aufrufen. Wenn Sie bestimmte Operationen nach der Erstellung von Objekten ausführen möchten und bevor der E/A -Vorgang stattfindet, ist diese Funktion für Sie sehr wichtig.
Viele Menschen verstehen die Verwendung von Process.NextTick () in node.js. Schauen wir uns an, welchen Prozess.NextTick () ist und wie man ihn benutzt.
Node.js ist Single-Threaded. Mit Ausnahme von System -IO wird während des Event -Wahlverfahrens nur ein Ereignis gleichzeitig verarbeitet. Sie können sich Ereignisabfragen als große Warteschlange vorstellen. Zu jedem Zeitpunkt verarbeitet das System nur ein Ereignis.
Selbst wenn Ihr Computer über mehrere CPU -Kerne verfügt, können Sie nicht gleichzeitig mehrere Ereignisse parallel verarbeiten. Diese Funktion macht Node.js jedoch für die Verarbeitung von E/A -Anwendungen geeignet, jedoch nicht für CPU -Computeranwendungen.
In jeder E/A -Anwendung müssen Sie nur eine Rückruffunktion für jede Eingabe und Ausgabe definieren, und sie werden automatisch in die Warteschlange zur Verarbeitung von Ereignissen hinzugefügt.
Wenn die E/A -Operation abgeschlossen ist, wird diese Rückruffunktion ausgelöst. Das System wird dann weiterhin andere Anfragen bearbeiten.
In diesem Verarbeitungsmodus bedeutet process.nextTick (), eine Aktion zu definieren und diese Aktion zu dem Zeitpunkt der nächsten Veranstaltung auszuführen. Schauen wir uns ein Beispiel an. Im Beispiel gibt es einen Foo (), den Sie zum nächsten Zeitpunkt anrufen möchten. Sie können dies tun:
Die Codekopie lautet wie folgt:
Funktion foo () {
console.Error ('foo');
}
process.nextTick (foo);
console.Error ('bar');
Führen Sie den obigen Code aus und Sie werden sehen, dass die Ausgabe von "Balken" vor "Foo" liegt. Dies überprüft die obige Aussage, die Foo () zum nächsten Zeitpunkt läuft.
Die Codekopie lautet wie folgt:
Bar
Foo
Sie können auch die Funktion setTimeout () verwenden, um denselben Ausführungseffekt zu erzielen:
Die Codekopie lautet wie folgt:
setTimeout (foo, 0);
console.log ('bar');
In Bezug auf den internen Verarbeitungsmechanismus sind process.nexttick () und setTimeout (fn, 0) jedoch unterschiedlich. process.nextTick () ist keine einfache Verzögerung, es hat mehr Funktionen.
Genauer gesagt erstellt der von Process.NextTick () definierte Aufruf einen neuen Substack. Im aktuellen Stack können Sie so viele Vorgänge ausführen, wie Sie möchten. Sobald Netxtick aufgerufen wurde, muss die Funktion an den übergeordneten Stapel zurückgegeben werden. Dann wartet der Event -Polling -Mechanismus darauf, dass neue Ereignisse erneut verarbeitet werden. Wenn NextTick gefunden wird, wird ein neuer Stapel erstellt.
Schauen wir uns an, welche Umstände der Prozess verwendet werden können.NextTick ():
Cross-execute CPU-operativintensive Aufgaben bei mehreren Veranstaltungen:
Im folgenden Beispiel gibt es einen Computer (). Wir hoffen, dass diese Funktion so kontinuierlich wie möglich ausgeführt wird, um einige operativintensive Aufgaben auszuführen.
Gleichzeitig hoffen wir aber auch, dass das System nicht durch diese Funktion blockiert wird und auch in der Lage sein wird, andere Ereignisse zu reagieren und umzugehen. Dieses Anwendungsmuster ist wie ein einzelner Thread -Webdienstserver. Hier können wir Process.NextTick () verwenden, um compute () und normale Ereignisreaktion zu zentrieren.
Die Codekopie lautet wie folgt:
var http = required ('http');
Funktion compute () {
// führt komplizierte Berechnungen kontinuierlich durch
// ...
process.nextTick (Computer);
}
http.createServer (Funktion (req, res) {{
Res.WriteHead (200, {'Inhalts-Typ': 'Text/Plain'});
res.end ('Hallo Welt');
}). Hören (5000, '127.0.0.1');
berechnen();
In diesem Modus müssen wir compute () nicht rekursiv aufrufen. Wir müssen nur process.nextTick () verwenden, um compute () zum nächsten Zeitpunkt der Ereignisschleife auszuführen.
Während dieses Vorgangs wird der Ereignisschleifungsmechanismus zuerst die neue Anfrage verarbeitet und dann compute () aufgerufen, wenn eine neue HTTP -Anfrage eingeht.
Im Gegenteil, wenn Sie compute () in einen rekursiven Aufruf einfügen, wird das System in compute () blockiert und kann neue HTTP -Anforderungen nicht bearbeiten. Sie können es selbst ausprobieren.
Natürlich können wir nicht die wirklichen Vorteile der parallelen Ausführung unter mehreren CPUs durch Process.NextTick () erzielen, um dieselbe Anwendung zu simulieren, die in Segmenten auf der CPU ausgeführt wird.
(2), Konsole
Konsole {Objekt} wird zum Drucken von StDout und Stderr. Sehen Sie den Abschnitt STDIO.
Konsole {Objekt} wird verwendet, um auf Standardausgabe und Fehlerausgabe zu drucken. Siehe den folgenden Test:
Die Codekopie lautet wie folgt:
console.log ("Hallo Bigbear!");
für (var i in der Konsole) {
console.log (i+""+console [i]);
}
Die folgenden Ausgabeergebnisse werden erhalten:
Die Codekopie lautet wie folgt:
var log = function () {
process.stdout.write (format.apply (this, argumente) + '/n');
}
var info = function () {
process.stdout.write (format.apply (this, argumente) + '/n');
}
var warn = function () {
writeError (format.apply (this, argumente) + '/n');
}
var error = function () {
writeError (format.apply (this, argumente) + '/n');
}
var Dir = Funktion (Objekt) {
var util = require ('util');
process.stdout.write (util.inspect (object) + '/n');
}
var time = function (label) {
Times [Label] = Datum.Now ();
}
var timeend = function (label) {
var duration = date.now () - mal [label];
exports.log ('undefined: nanms', Etikett, Dauer);
}
var trece = function (label) {
// Todo kann dies wahrscheinlich besser mit dem Debug -Objekt von V8 machen, sobald das ist
// ausgesetzt.
var err = neuer Fehler;
err.name = 'trace';
err.message = label || '';
ERROR.CAPTURESTACKTRACE (Err, Argumente.Callee);
console.Error (err.stack);
}
var assert = function (Expression) {
if (! Ausdruck) {
var arr = array.prototype.slice.call (Argumente, 1);
erfordern ('assert'). OK (falsch, format.Apply (this, arr));
}
}
Durch diese Funktionen wissen wir im Grunde genommen, was Nodejs zum globalen Bereich beigetragen hat. Tatsächlich verkapulieren die relevanten APIs auf dem Konsolenobjekt nur die "stdout.write" am Prozessobjekt und hängen Sie es an das globale Objekt.
(3) Exporte und Module.exports
In NodeJs gibt es zwei Bereiche, die in den globalen Bereich und den Modulbereich unterteilt sind
Die Codekopie lautet wie folgt:
var name = 'var-name';
name = 'name';
global.name = 'global-name';
this.name = 'Modul-name';
console.log (global.name);
console.log (this.name);
console.log (name);
Wir sehen, dass var name = 'var-name'; name = 'name'; ist eine definierte lokale Variable;
global.name = 'global-name'; Definiert ein Namensattribut für das globale Objekt.
Und this.name = 'Modulname'; Definiert ein Namensattribut für das Modulobjekt
Überprüfen wir es also, speichern Sie Folgendes als Test2.js und führen Sie es aus
Die Codekopie lautet wie folgt:
var t1 = require ('./ Test1');
console.log (t1.name);
console.log (global.name);
Wie aus den Ergebnissen hervorgeht, haben wir das Test1 -Modul erfolgreich importiert und den Test1 -Code ausgeführt, da global.name in test2 ausgegeben wird.
T1.Name ist im TEST1 -Modul über diesen NAME definiert, was darauf hinweist, dass dies auf das Modul -Scope -Objekt hinweist.
Ein kleiner Unterschied zwischen Exporten und Modul.exports
Module.exports ist die reale Schnittstelle, und Exporte ist nur ein Hilfsmittel dafür. Die endgültige Rückkehr zum Anruf ist Module.exports anstelle von Exporten.
Alle von Exporten gesammelten Eigenschaften und Methoden werden Module.exports zugeordnet. Natürlich gibt es dafür eine Voraussetzung, dh Module.exports本身不具备任何属性和方法。
如果, Module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。
Nehmen Sie eine Kastanie:
Erstellen Sie eine neue Datei bb.js
Die Codekopie lautet wie folgt:
exports.name = function () {
console.log ('Mein Name ist großer Bär!');
};
Erstellen Sie eine Testdatei test.js
Die Codekopie lautet wie folgt:
var bb = required ('./ Bb.js');
bb.name (); // 'Mein Name ist Big Bear! ''
Ändern Sie BB.js wie folgt:
Die Codekopie lautet wie folgt:
Module.exports = 'Bigbear!' ;
exports.name = function () {
console.log ('Mein Name ist großer Bär!');
};
Weitere Informationen finden Sie erneut BB.js
Die Codekopie lautet wie folgt:
var bb = required ('./ Bb.js');
bb.name (); // hat keine Methode 'Name' '
Daraus können wir erkennen, dass Ihr Modul nicht unbedingt ein "eingeleitetes Objekt" zurückgeben muss. Ihr Modul kann ein legales JavaScript -Objekt sein -Boolan, Nummer, Datum, JSON, String, Funktion, Array usw.
(4), setTimeout, setInterval, process.nextTick, setImmediate
Das Folgende ist in Form einer Zusammenfassung
NodeJs ist durch ereignisgesteuerte, hohe Genauigkeit charakterisiert, die durch asynchrones E/A erzeugt wird. Der Motor, der diese Funktion erzeugt, ist eine Ereignisschleife. Ereignisse werden in entsprechende Ereignisbeobachter wie Leerlaufbeobachter, Timerbeobachter, E/A -Beobachter usw. eingeteilt. Jede Schleife der Ereignisschleife wird als Zecke bezeichnet. Jede Zecke nimmt Ereignisse aus den Ereignisbeobachtern nacheinander zur Verarbeitung.
Der Timer, der beim Aufrufen von setTimeout () oder setInterval () erstellt wurde, wird in den roten und schwarzen Baum im Timer -Observer platziert. Jedes Mal, wenn Sie ankreuzen, wird prüfen, ob der Timer die Timing -Zeit vom roten und schwarzen Baum überschritten hat. Wenn es das Timing überschreitet, wird die entsprechende Rückruffunktion sofort ausgeführt. setTimeout () und setInterval () werden beide von Timern verwendet. Der Unterschied besteht darin, dass letzteres wiederholt ausgelöst wird und da die Zeiteinstellung zu kurz ist, wird die Verarbeitung nach dem vorherigen Auslöser unmittelbar nach Abschluss des vorherigen Auslösers ausgelöst.
Da es sich bei dem Timer um einen Auslöser von Zeitlagen handelt, verringert dies die Auslösergenauigkeit. Beispielsweise beträgt die Zeitlimitzeit mit SetTimeout 5 Sekunden. Wenn die Ereignisschleife in der 4. Sekunde eine Aufgabe durchläuft und seine Ausführungszeit 3 Sekunden beträgt, läuft die SetTimeout -Rückruffunktion 2 Sekunden lang ab, was der Grund für die Reduzierung der Genauigkeit ist. Und weil die Timer- und Urteilsauslöser unter Verwendung von roten und schwarzen Bäumen und iterativen Methoden gerettet werden, ist es eine Leistungsverschwendung.
Alle Rückruffunktionen, die mit Process.NextTick () festgelegt werden, werden im Array platziert und alle werden sofort auf dem nächsten Ticken ausgeführt. Dieser Vorgang ist leicht und hat eine hohe Zeitgenauigkeit.
Die von setimmediate () festgelegte Rückruffunktion ist auch beim nächsten Tick aufgerufen. Der Unterschied zwischen IT und Process.NextTick () beträgt zwei Punkte:
1. Die Priorität der Ausführung des Beobachters, zu dem sie angehören, ist anders. Process.nextTick () gehört zum Leerlaufbeobachter, SetImmediate () gehört zum Check -Beobachter und Priorität des Leerlaufs> Überprüfung.
2. Die von setimmediate () festgelegte Rückruffunktion wird in einer verknüpften Liste platziert, und jedes Mal wird in der verlinkten Liste nur ein Rückruf ausgeführt. Dies soll sicherstellen, dass jede Zecke schnell ausgeführt werden kann.
Zweitens, lasst uns zusammenfassen
1. Verstehen Sie die Bedeutung der Existenz globaler Objekte
2. Ein wenig Unterschied zwischen Exporten und Modul.exports
3. Was ist die zugrunde liegende Konsolenschicht (Aufkapselung von Prozessobjekten auf hoher Ebene)
4. Der Unterschied zwischen SetTimeout, setInterval, process.nextTick, setImmediate
5. Zwei Bereiche in Nodejs