Im Knoten emittieren viele Objekte Ereignisse. Beispielsweise überträgt ein TCP -Server ein "Connect" -Ereignis, wenn ein Client eine Verbindung anfordert, und beispielsweise überträgt das Dateisystem ein "Daten" -Ereignis. Diese Objekte werden als Ereignisemitter im Knoten bezeichnet. Mit dem Ereignistransmitter können Programmierer Ereignisse von Interesse abonnieren und die Rückruffunktion an die zugehörigen Ereignisse binden, so dass die Rückruffunktion aufgerufen wird, wenn der Ereignissender ein Ereignis ausgibt. Der Veröffentlichung/Abonnement -Modus ist dem herkömmlichen GUI -Modus sehr ähnlich, wie z. B. das Programm erhält entsprechende Benachrichtigungen, wenn die Schaltfläche klickt. Mit diesem Modell können Serverprogramme reagieren, wenn einige Ereignisse auftreten, z. B. die Clientverbindung, Daten, die in der Socket verfügbar sind oder die Datei geschlossen sind.
Sie können auch Ihren eigenen Veranstaltungssender erstellen. Tatsächlich bietet Node eine spezielle Pseudoklasse für EventEmitter, die als Basisklasse verwendet werden kann, um einen eigenen Event-Sender zu erstellen.
Den Rückrufmodus verstehen
Die asynchrone Programmierung verwendet keine Funktionsrückgabewerte, um das Ende eines Funktionsaufrufs anzuzeigen, sondern nimmt jedoch einen nachfolgenden Passstil an.
"Continuation-Passing-Stil" (CPS: Continuation-Passing-Stil) ist ein Programmierstil, und die Prozesssteuerung wird explizit an die nächste Operation übergeben ...
Funktionen im CPS-Stil akzeptieren eine Funktion als zusätzlichen Parameter. Diese Funktion wird verwendet, um explizit auf den nächsten Prozess der Programmsteuerung hinzuweisen. Wenn die CPS -Funktion ihren "Rückgabewert" berechnet, wird die Funktion aufgerufen, die den nächsten Prozess des Programms darstellt und den "Rückgabewert" der CPS -Funktion als Parameter nimmt.
Von wikipedia - http://en.wikipedia.org/wiki/continuation-passing_style
In diesem Programmierstil ruft jede Funktion nach der Ausführung eine Rückruffunktion auf, sodass das Programm weiter ausgeführt werden kann. Sie werden später verstehen, dass JavaScript für diesen Programmierstil sehr geeignet ist. Hier ist ein Beispiel für das Laden von Dateien in den Speicher unter dem Knoten:
Die Codekopie lautet wie folgt:
var fs = fordert ('fs');
fs.ReadFile ('/etc/passwd', Funktion (err, filecontent) {
if (err) {
errösten;
}
console.log ('Dateiinhalt', fileContent.toString ());
});
In diesem Beispiel übergeben Sie eine anonyme inline -Funktion als zweiter Parameter von FS.Readfile. In der Tat wird die CPS -Programmierung verwendet, da Sie den nachfolgenden Prozess der Programmausführung an die Rückruffunktion übergeben.
Wie Sie sehen können, ist der erste Parameter der Rückruffunktion ein Fehlerobjekt. Wenn im Programm ein Fehler auftritt, ist dieser Parameter eine Instanz der Fehlerklasse. Dies ist ein gemeinsames Muster für die CPS -Programmierung im Knoten.
Ereignisübertragungsmodus verstehen
Im Standard -Rückrufmodus wird eine Funktion als Parameter an die zu ausgeführte Funktion übergeben. Dieser Modus funktioniert sehr gut in Szenarien, in denen der Client nach Abschluss der Funktion benachrichtigt werden muss. Wenn jedoch während der Ausführung einer Funktion oder Ereignisse mehrmals mehrere Ereignisse auftreten, ist dieses Muster nicht geeignet. Wenn Sie beispielsweise jedes Mal benachrichtigt werden möchten, wenn der Socket verfügbare Daten erhält, werden Sie feststellen, dass der Standard -Rückrufmodus in diesem Szenario nicht sehr nützlich ist. Zu diesem Zeitpunkt ist der Event -Sendermodus nützlich. Sie können eine Reihe von Standardschnittstellen verwenden, um den Ereignisgenerator und den Ereignishörer klar zu trennen.
Bei der Verwendung des Ereignisgeneratormodus sind zwei oder mehr Objekte beteiligt - Event -Sender und eine oder mehrere Ereignishörer.
Ein Ereignissender ist, wie der Name schon sagt, ein Objekt, das Ereignisse generieren kann. Der Ereignishörer ist Code, der an den Ereignissender gebunden ist, um bestimmte Arten von Ereignissen wie das folgende Beispiel anzuhören:
Die Codekopie lautet wie folgt:
var req = http.request (Optionen, Funktion (Antwort) {
response.on ("Daten", Funktion (Daten) {
console.log ("Einige Daten aus der Antwort", Daten);
});
response.on ("end", function () {
console.log ("Antwort beendet");
});
});
req.end ();
Dieser Code zeigt zwei erforderliche Schritte beim Erstellen einer HTTP -Anforderung zum Zugriff auf einen Remote -HTTP -Server mithilfe der HTTP.Request -API von Node (siehe späteres Kapitel). Die erste Zeile übernimmt den "Continuation-Passing-Stil" (CPS: Continuation-Passing-Stil) und überträgt eine Inline-Funktion, die aufgerufen wird, wenn HTTP reagiert. Die HTTP -Request -API verwendet CPS hier, da das Programm weiterhin nachfolgende Vorgänge ausführen muss, nachdem die Funktion HTTP.Request ausgeführt wurde.
Wenn http.request ausgeführt wird, wird die anonyme Rückruffunktion aufgerufen und das HTTP -Antwortobjekt wird als Parameter an sie übergeben. Dieses HTTP -Antwortobjekt ist ein Ereignissender. Laut dem Knotendokument kann es viele Ereignisse wie Daten und Ende ausgeben. Die von Ihnen registrierten Rückruffunktionen werden jedes Mal aufgerufen, wenn das Ereignis auftritt.
Verwenden Sie als Lektion den CPS -Modus, wenn Sie nach Abschluss des angeforderten Betriebs die Ausführungsrechte wiedererlangen müssen, und verwenden Sie den Ereignis -Sendermodus, wenn Ereignisse mehrmals auftreten können.
Ereignisarten verstehen
Die übertragenen Ereignisse haben einen Typ, der durch eine Zeichenfolge dargestellt wird. Das vorherige Beispiel enthält zwei Ereignisarten: "Daten" und "Ende", bei denen es sich um Zeichenfolgen handelt, die vom Ereignissender definiert sind. Es ist jedoch herkömmlich konstitutiv, dass Ereignisarten normalerweise aus Kleinbuchstaben zusammengesetzt sind, die keine leeren Zeichen enthalten.
Sie können keinen Code verwenden, um zu schließen, welche Arten von Ereignissen der Ereignis -Sender generieren kann, da die Ereignistransmitter -API keinen Selbstbeobachtungsmechanismus aufweist. Die von Ihnen verwendete API sollte daher eine Dokumentation haben, um anzuzeigen, dass diese Art von Ereignissen emittiert werden kann.
Sobald ein Ereignis auftritt, ruft der Ereignissender den Listener auf, der sich auf das Ereignis bezieht und die entsprechenden Daten an den Hörer als Parameter übergeben wird. Im vorherigen Beispiel akzeptiert Http.request die "Daten" -Event -Rückruffunktion ein Datenobjekt als erstes und einziger Parameter, während "Ende" keine Daten akzeptiert. Diese Parameter im Rahmen des API -Vertrags werden auch vom Autor der API subjektiv definiert. Die Parametersignaturen dieser Rückruffunktionen werden auch in der API -Dokumentation jedes Ereignisemitters erläutert.
Obwohl der Event -Sender eine Schnittstelle ist, die alle Arten von Ereignissen bedient, ist das "Fehler" -Ereignis eine spezielle Implementierung im Knoten. Die meisten Ereignissender im Knoten generieren ein "Fehler" -Ereignis, wenn im Programm ein Fehler auftritt. Wenn das Programm nicht auf das "Fehler" -Ereigner eines Ereignissenders hört, bemerkt und wirft der Ereignissender eine ungekordene Ausnahme nach oben, wenn der Fehler auftritt.
Sie können den folgenden Code im Knoten Perl ausführen, um den Effekt zu testen, der einen Ereignissender simuliert, der zwei Ereignisse generieren kann:
Die Codekopie lautet wie folgt:
var em = new (fordert ('Ereignisse'). EventEmitter) ();
em.emit ('event1');
Em.Emit ('Fehler', neuer Fehler ('mein Fehler'));
Sie sehen die folgende Ausgabe:
Die Codekopie lautet wie folgt:
var em = new (fordert ('Ereignisse'). EventEmitter) ();
undefiniert
> em.emit ('event1');
FALSCH
> em.emit ('Fehler', neuer Fehler ('mein Fehler'));
Fehler: Mein Fehler
bei Repl: 1: 18
bei replServer.eval (repl.js: 80: 21)
bei repl.js: 190: 20
bei replServer.eval (repl.js: 87: 5)
an der Schnittstelle. <anonymous> (repl.js: 182: 12)
at interface.emit (Ereignisse.js: 67: 17)
at interface._online (readline.js: 162: 10)
at interface._line (readline.js: 426: 8)
at interface._ttywrite (readline.js: 603: 14)
bei ReadStream. <Anonymous> (Readline.js: 82: 12)
>
In Zeile 2 des Codes wird ein Ereignis namens "Event1" ohne Wirkung emittiert, aber wenn das "Fehler" -Ereignis emittiert wird, wird der Fehler in den Stapel geworfen. Wenn das Programm nicht in der Perl -Befehlszeilenumgebung ausgeführt wird, stürzt das Programm aufgrund einer ungewöhnlichen Ausnahme ab.
Verwenden der Event -Sender -API
Jedes Objekt, das den Ereignistransmittermodus (z. B. TCP -Socket, HTTP -Anforderung usw.) implementiert, implementiert die folgenden Methodenmenge:
Die Codekopie lautet wie folgt:
.AddListener und .on - Fügen Sie Event -Listener für Ereignisse des angegebenen Typs hinzu
.once - Binden Sie einen Ereignishörer, der nur einmal für den Ereignis des angegebenen Typs ausgeführt wird
.RemoveEventListener - Löschen Sie einen an das angegebenen Ereignis gebundenen Hörer
.RemovealleventListener - Löschen Sie alle an das angegebenen Ereignis gebundenen Hörer
Lassen Sie uns sie unten ausführlich vorstellen.
Bindungsrückruffunktionen mit .AddListener () oder .on ()
Durch Angeben der Ereignisentyp- und Rückruffunktion können Sie die nach dem Ereignis erfolgen erfüllten Aktionen registrieren. Wenn beispielsweise Datenblöcke verfügbar sind, wenn eine Datei einen Datenstrom liest, wird ein "Daten" -Ereignis ausgegeben. Der folgende Code zeigt, wie Sie eine Rückruffunktion übergeben, um das Programm Ihnen mitzuteilen, dass das Datenereignis aufgetreten ist.
Die Codekopie lautet wie folgt:
Funktion empfangeneata (Daten) {
console.log ("Daten aus dem Datei -Lese -Stream erhalten: %j", Daten);
}
readStream.addListener ("Daten", empfangene);
Sie können auch .on auch verwenden, was nur die Abkürzung von .AddListener ist. Der folgende Code entspricht dem oben genannten:
Die Codekopie lautet wie folgt:
Funktion empfangeneata (Daten) {
console.log ("Daten aus dem Datei -Lese -Stream erhalten: %j", Daten);
}
ReadStream.on ("Daten", empfangeneata);
Im vorherigen Code können Sie eine benannte Funktion verwenden, die im Voraus als Rückruffunktion definiert ist, und Sie können auch eine anonyme inline -Funktion verwenden, um den Code zu vereinfachen:
Die Codekopie lautet wie folgt:
ReadStream.on ("Daten", Funktion (Daten) {
console.log ("Daten aus dem Datei -Lese -Stream erhalten: %j", Daten);
});
Wie bereits erwähnt, hängt die Anzahl der an die Rückruffunktion übergebenen Parameter und Signaturen vom spezifischen Ereignistransmitterobjekt und Ereignis Typ ab. Sie sind nicht standardisiert. Das "Daten" -Ereignis kann ein Datenpufferobjekt übergeben, das "Fehler" -Ereignis übergibt ein Fehlerobjekt, und das "End" -Ereignis des Datenflusss übergibt keine Daten an den Ereignishörer.
Binden Sie mehrere Ereignishörer
Mit dem Event -Sender -Modus können mehrere Ereignishörer auf denselben Ereignisstyp desselben Ereignis -Senders anhören, wie z. B.:
Die Codekopie lautet wie folgt:
Ich habe hier einige Daten.
Ich habe auch hier einige Daten.
Der Event -Sender ist dafür verantwortlich, alle an den angegebenen Ereignisentypen gebundenen Hörer in der Reihenfolge zu berufen, in der der Hörer registriert ist, dh:
1. Wenn ein Ereignis auftritt, wird der Ereignishörer möglicherweise nicht sofort aufgerufen, und es können andere Ereignishörer vor ihm angegeben werden.
2. Es ist abnormal, in den Stapel geworfen zu werden, was auf einen Fehler im Code zurückzuführen ist. Wenn ein Ereignis übertragen wird und ein Ereignishörer eine Ausnahme ausführt, wenn es aufgerufen wird, werden einige Ereignishörer möglicherweise nie aufgerufen. In diesem Fall fängt der Event -Sender die Ausnahme ein und kann auch damit umgehen.
Siehe das folgende Beispiel:
Die Codekopie lautet wie folgt:
ReadStream.on ("Daten", Funktion (Daten) {
Neuen Fehler werfen ("etwas falsch ist passiert");
});
ReadStream.on ("Daten", Funktion (Daten) {
console.log ('Ich habe auch einige Daten hier.');
});
Da der erste Hörer eine Ausnahme ausgelegt hat, wird der zweite Hörer nicht aufgerufen.
Verwenden Sie .Removelistener (), um einen Ereignishörer aus dem Event -Sender zu entfernen
Wenn Sie sich nicht mehr für ein Ereignis eines Objekts interessieren, können Sie den registrierten Ereignishörer absagen, indem Sie die Ereignisentyp- und Rückruffunktion wie folgt angeben:
Die Codekopie lautet wie folgt:
Funktion empfangeneata (Daten) {
console.log ("Daten aus dem Datei -Lese -Stream erhalten: %j", Daten);
}
ReadStream.on ("Daten", empfangeneata);
// ...
readStream.removelistener ("Daten", empfangene);
In diesem Beispiel entfernt die letzte Zeile einen Ereignishörer, der in Zukunft jederzeit aus dem Ereignis -Sender -Objekt aufgerufen werden kann.
Um den Listener zu löschen, müssen Sie die Rückruffunktion benennen, da der Name der Rückruffunktion beim Hinzufügen und Löschen erforderlich ist.
Verwenden Sie .once (), damit die Rückruffunktion höchstens einmal ausgeführt werden kann
Wenn Sie auf ein Ereignis zuhören möchten, das höchstens einmal ausgeführt wird oder nur an dem ersten Mal interessiert ist, dass ein Ereignis auftritt, können Sie die Funktion .once () verwenden:
Die Codekopie lautet wie folgt:
Funktion empfangeneata (Daten) {
console.log ("Daten aus dem Datei -Lese -Stream erhalten: %j", Daten);
}
ReadStream.once ("Daten", empfangeneata);
Im obigen Code wird die empfangene Funktion nur einmal aufgerufen. Wenn das ReadStream -Objekt ein Datenereignis abgibt, wird die Empfangs -Rückruffunktion nur einmal ausgelöst.
Es ist eigentlich nur eine bequeme Methode, da sie sehr einfach implementiert werden kann:
Die Codekopie lautet wie folgt:
var EventEmitter = Request ("Events"). EventEmitter;
EventEmitter.prototype.once = function (type, callback) {
var das = dies;
this.on (type, function louser () {
that.removelistener (Typ, Hörer);
Callback.Apply (das, Argumente);
});
};
Im obigen Code definieren Sie die Funktion eventEmitter.prototype.once und definieren Sie auch die einmalige Funktion jedes von EventEmitter geerbten Objekts. Der Code verwendet einfach die Methode .on (). Sobald eine Veranstaltung empfangen wurde, verwenden Sie .RemoveEventListener (), um die Registrierung der Rückruffunktion zu stornieren und die ursprüngliche Rückruffunktion aufzurufen.
HINWEIS: Der vorherige Code verwendet die function.apply () -Methode, die ein Objekt akzeptiert und als die enthaltene Variable und ein Array von Parametern annimmt. Im vorherigen Beispiel wird das nicht modifizierte Parameterarray transparent über den Ereignissender an die Rückruffunktion übergeben.
Entfernen Sie alle Event -Hörer vom Event -Sender mit .RemoveAlllisteners ()
Sie können alle Hörer wie folgt vom angegebenen Ereignisentyp aus dem Ereignis -Sender entfernen:
Die Codekopie lautet wie folgt:
Emitter.RemoveAlllisteners (Typ);
Beispielsweise können Sie den Hörer aller Prozess -Interrupt -Signale wie folgt abbrechen:
Die Codekopie lautet wie folgt:
process.removealllisteners ("sigterm");
Hinweis: Als Lektion wird empfohlen, diese Funktion nur zu verwenden, wenn Sie genau wissen, was gelöscht wird. Andernfalls sollten Sie andere Teile der Anwendung die Sammlung von Event -Listener löschen lassen, oder Sie können auch die Teile des Programms für die Entfernung des Hörers selbst übernehmen lassen. Aber egal was passiert, diese Funktion ist in einigen seltenen Szenarien immer noch nützlich, z.
Erstellen Sie einen Ereignis -Sender
Eventsender machen Programmierschnittstellen auf großartige Weise allgemeiner. In einem gemeinsamen und leicht verständlichen Programmiermodus ruft der Client direkt verschiedene Funktionen auf, während der Client im Event-Sendermodus an verschiedene Ereignisse gebunden ist, wodurch Ihr Programm flexibler wird. (Anmerkung des Übersetzers: Dieser Satz ist nicht sehr selbstbewusst, indem Sie den Originaltext veröffentlichen: Der Ereignisemitter bietet eine gute Möglichkeit, eine Programmierschnittstelle generischer zu gestalten. Wenn Sie ein gemeinsames Verständnismuster verwenden, binden die Clients an Ereignisse, anstatt Funktionen aufzurufen und Ihr Programm flexibler zu machen.)
Darüber hinaus können Sie durch die Verwendung von Ereignissendern viele Funktionen erhalten, z. B. das Binden mehrerer nicht verwandter Hörer an derselben Veranstaltung.
Vom Knoten -Event -Sender geerbt
Wenn Sie sich für den Event-Emittermodus von Node interessieren und beabsichtigen, ihn in Ihrer eigenen Anwendung zu verwenden, können Sie eine Pseudoklasse erstellen, indem Sie Eventemitter erben:
Die Codekopie lautet wie folgt:
util = fordert ('util');
var eventEmitter = required ('events'). eventEmitter;
// Dies ist der Konstruktor der MyClass:
var myclass = function () {
}
util.inherits (MyClass, Eventemitter);
Hinweis: Util.inherits erstellt die Prototyp -Kette von MyClass, so dass Ihre MyClass -Instanz die Prototyp -Methode von EventEmitter verwenden kann.
Startveranstaltung
Durch Erben von EventEmitter kann MyClass Events wie folgt starten:
Die Codekopie lautet wie folgt:
Myclass.prototype.somemethod = function () {
this.emit ("benutzerdefiniertes Ereignis", "Argument 1", "Argument 2");
};
In dem obigen Code wird ein Ereignis namens "Cuteom Event" ausgestrahlt, wenn die Methode von der Zeit von der MyClass -Instanz aufgerufen wird. Dieses Ereignis wird auch zwei Zeichenfolgen als Daten ausgeben: "Argument 1" und "Argument 2", die als Parameter an den Ereignishörer übergeben werden.
Der Kunde der MyClass -Instanz kann für das "benutzerdefinierte Ereignis" wie folgt zuhören:
Die Codekopie lautet wie folgt:
var myinstance = new myclass ();
myInstance.on ('benutzerdefinierter Ereignis', Funktion (str1, str2) {
console.log ('bekommen ein benutzerdefiniertes Ereignis mit Str1 %s und str2 %s!', str1, str2);
});
Sie können beispielsweise eine Tickerklasse erstellen, die "Tick" -Ereignisse einmal in einer Sekunde ausgibt:
Die Codekopie lautet wie folgt:
var util = require ('util'),
EventEmitter = Request ('Events'). EventEmitter;
var ticker = function () {
var self = this;
setInterval (function () {
self.emit ('tick');
}, 1000);
};
util.inherits (Ticker, Eventemitter);
Clients, die die Ticker -Klasse verwenden, können angeben, wie Sie die Tickerklasse verwenden und für "Tick" -Events anhören.
Die Codekopie lautet wie folgt:
var Ticker = neuer Ticker ();
Ticker.on ("tick", function () {
console.log ("tick");
});
Zusammenfassung
Der Event -Sender -Modus ist ein Wiedereinzugsmuster, mit dem das Ereignistransmitterobjekt für ein bestimmtes Ereignis von einem Code -Satz von Code entschieden werden kann.
Sie können Event_emitter.on () verwenden, um die Hörer für bestimmte Arten von Ereignissen zu registrieren und mit Event_emitter.removelistener () nicht zu registrieren.
Sie können auch Ihren eigenen Event -Emitter erstellen, indem Sie Eventemitter erben und einfach die Funktion .emit () verwenden.