Toen ik voor het eerst over Node.js hoorde, dacht ik dat het gewoon een JavaScript-implementatie voor de server was. Maar het is eigenlijk veel meer: het wordt geleverd met een groot aantal ingebouwde functies die u niet in de browser krijgt. Een van die stukjes functionaliteit is de Event Module, die de EventEmitter
klasse. We zullen daarnaar kijken in deze tutorial.
EventEmitter
: Wat en waaromDus, wat precies doet het EventEmitter
klas doen? Simpel gezegd, hiermee kunt u luisteren naar "evenementen" en acties toewijzen om uit te voeren wanneer die gebeurtenissen plaatsvinden. Als u bekend bent met front-end JavaScript, weet u wat er gebeurt met muis- en toetsenbordgebeurtenissen die optreden bij bepaalde gebruikersinteracties. Deze lijken erg op elkaar, behalve dat we alleen gebeurtenissen kunnen uitzenden wanneer we dat willen en niet noodzakelijk op basis van gebruikersinteractie. De principes EventEmitter
is gebaseerd op het model publish / subscribe, omdat we ons kunnen abonneren op evenementen en deze vervolgens kunnen publiceren. Er zijn veel front-end bibliotheken gebouwd met pub / sub-ondersteuning, maar Node heeft het ingebouwd.
De andere belangrijke vraag is deze: waarom zou u het gebeurtenismodel gebruiken? In Node is dit een alternatief voor diep geneste callbacks. Veel Node-methoden worden asynchroon uitgevoerd, wat betekent dat als u code wilt uitvoeren nadat de methode is voltooid, u een callback-methode moet doorgeven aan de functie. Uiteindelijk zal uw code eruitzien als een gigantische trechter. Om dit te voorkomen, zenden veel knooppuntklassen gebeurtenissen uit waarnaar u kunt luisteren. Hiermee kunt u uw code indelen zoals u zou willen, en geen callbacks gebruiken.
Nog een voordeel voor evenementen: het is een heel losse manier om delen van uw code aan elkaar te koppelen. Er kan een evenement worden uitgezonden, maar als er geen code naar luistert, is dat in orde: het gaat gewoon onopgemerkt voorbij. Dit betekent dat het verwijderen van luisteraars (of gebeurtenisemissies) nooit resulteert in JavaScript-fouten.
EventEmitter
We beginnen met de EventEmitter
klasse op zichzelf. Het is vrij simpel om bij te geraken: we hebben alleen de evenementenmodule nodig:
var events = require ("events");
Deze events
object heeft één eigenschap, dat is de EventEmitter
klasse zelf. Laten we dus een eenvoudig voorbeeld geven voor starters:
var EventEmitter = require ("events"). EventEmitter; var ee = nieuwe EventEmitter (); ee.on ("someEvent", function () console.log ("event is occured");); ee.emit ( "eenGebeurtenis");
We beginnen met het maken van een nieuwe EventEmitter
voorwerp. Dit object heeft twee hoofdmethoden die we gebruiken voor evenementen: op
en uitzenden
.
We beginnen met op
. Deze methode heeft twee parameters nodig: we beginnen met de naam van de gebeurtenis waar we naar luisteren: in dit geval is dat "EenGebeurtenis"
. Maar het kan natuurlijk alles zijn, en je zult meestal iets beters kiezen. De tweede parameter is de functie die wordt aangeroepen wanneer de gebeurtenis plaatsvindt. Dat is alles dat nodig is voor het opzetten van een evenement.
Om het evenement te activeren, geeft u de naam van het evenement door aan de EventEmitter
-instantie uitzenden
methode. Dat is de laatste regel van de bovenstaande code. Als u die code uitvoert, ziet u dat de tekst wordt afgedrukt naar de console.
Dat is het meest basale gebruik van een EventEmitter
. U kunt ook gegevens opnemen bij het afvuren van gebeurtenissen:
ee.emit ("nieuwe gebruiker", userObj);
Dat is slechts één gegevensparameter, maar u kunt er zoveel toevoegen als u wilt. Om ze te gebruiken in uw gebeurtenishandlerfunctie, neemt u ze gewoon als parameters:
ee.on ("nieuwe gebruiker", functie (gegevens) // gebruik gegevens hier);
Alvorens verder te gaan, laat me een deel van de EventEmitter
functionaliteit. We kunnen meer dan één luisteraar hebben voor elke gebeurtenis; meerdere gebeurtenislisteners kunnen worden toegewezen (allemaal met op
) en alle functies worden opgeroepen wanneer de gebeurtenis wordt afgevuurd. Node staat standaard maximaal tien luisteraars toe op één evenement tegelijk; Als er meer worden gemaakt, geeft het knooppunt een waarschuwing. We kunnen dit bedrag echter wijzigen met behulp van setMaxListeners
. Als u dit bijvoorbeeld uitvoert, ziet u boven de uitvoer een waarschuwing afgedrukt:
ee.on ("someEvent", function () console.log ("event 1");); ee.on ("someEvent", function () console.log ("event 2");); ee.on ("someEvent", function () console.log ("event 3");); ee.on ("someEvent", function () console.log ("event 4");); ee.on ("someEvent", function () console.log ("event 5");); ee.on ("someEvent", function () console.log ("event 6");); ee.on ("someEvent", function () console.log ("event 7");); ee.on ("someEvent", function () console.log ("event 8");); ee.on ("someEvent", function () console.log ("event 9");); ee.on ("someEvent", function () console.log ("event 10");); ee.on ("someEvent", function () console.log ("event 11");); ee.emit ( "eenGebeurtenis");
Om het maximale aantal kijkers in te stellen, voegt u deze regel boven de luisteraars toe:
ee.setMaxListeners (20);
Als je het nu uitvoert, krijg je geen waarschuwing.
EventEmitter
methodenEr zijn er nog een paar EventEmitter
methoden die u handig vindt.
Hier is een nette: een keer
. Het is net als het op
methode, behalve dat het maar één keer werkt. Nadat de luisteraar voor het eerst is gebeld, wordt deze verwijderd.
ee.conce ("firstConnection", function () console.log ("U zult dit nooit meer zien");); ee.emit ( "firstConnection"); ee.emit ( "firstConnection");
Als u dit uitvoert, wordt het bericht slechts één keer weergegeven. De tweede uitzending van het evenement wordt niet opgepikt door luisteraars (en dat is oké trouwens), omdat het een keer
luisteraar werd verwijderd na één keer te zijn gebruikt.
Spreken van het verwijderen van luisteraars, we kunnen dit zelf doen, manueel, op een paar manieren. Ten eerste kunnen we een enkele luisteraar verwijderen met de removeListener
methode. Er zijn twee parameters nodig: de naam van de gebeurtenis en de luisterfunctie. Tot nu toe hebben we anonieme functies gebruikt als onze luisteraars. Als we later een luisteraar willen kunnen verwijderen, moet deze een functie zijn met een naam waarnaar we kunnen verwijzen. We kunnen dit gebruiken removeListener
methode om de effecten van de te dupliceren een keer
methode:
function onlyOnce () console.log ("U zult dit nooit meer zien"); ee.removeListener ("firstConnection", onlyOnce); ee.on ("firstConnection", onlyOnce) ee.emit ("firstConnection"); ee.emit ( "firstConnection");
Als je dit uitvoert, zul je zien dat het hetzelfde effect heeft als een keer
.
Als u alle luisteraars wilt verwijderen die aan een bepaalde gebeurtenis zijn gebonden, kunt u gebruiken removeAllListeners
; geef het gewoon de naam van het evenement:
ee.removeAllListeners ( "firstConnection");
Om alle luisteraars voor alle gebeurtenissen te verwijderen, roept u de functie zonder parameters aan.
ee.removeAllListeners ();
Er is nog een laatste methode: luisteraar
. Deze methode neemt een gebeurtenisnaam als een parameter en retourneert een array van alle functies die naar die gebeurtenis luisteren. Hier is een voorbeeld van, gebaseerd op onze onlyOnce
voorbeeld:
function onlyOnce () console.log (ee.listeners ("firstConnection")); ee.removeListener ("firstConnection", onlyOnce); console.log (ee.listeners ( "firstConnection")); ee.on ("firstConnection", onlyOnce) ee.emit ("firstConnection"); ee.emit ( "firstConnection");
We eindigen dit gedeelte met een beetje meta-ness. Onze EventEmitter
instance zelf vuurt eigenlijk twee eigen evenementen af, waar we naar kunnen luisteren: een wanneer we nieuwe luisteraars maken en een andere wanneer we ze verwijderen. Kijk hier:
ee.on ("newListener", function (evtName, fn) console.log ("New Listener:" + evtName);); ee.on ("removeListener", function (evtName) console.log ("Removed Listener:" + evtName);); function foo () ee.on ("save-user", foo); ee.removeListener ("save-user", foo);
Als je dit uitvoert, zie je onze luisteraars voor zowel nieuwe luisteraars als verwijderde luisteraars zijn uitgevoerd en krijgen we de berichten die we verwachtten.
Dus nu we alle methoden hebben gezien die een EventEmitter
instance heeft, laten we eens kijken hoe het werkt in combinatie met andere modules.
EventEmitter
Binnen ModulesSinds de EventEmitter
class is gewoon een standaard JavaScript, het is volkomen logisch dat het in andere modules kan worden gebruikt. In uw eigen JavaScript-modules kunt u creëren EventEmitter
instanties en gebruik deze om interne gebeurtenissen af te handelen. Dat is eenvoudig. Interessanter is om een module te maken die erft EventEmitter
, zodat we het functionaliteitsgedeelte van de openbare API kunnen gebruiken.
Eigenlijk zijn er ingebouwde Node-modules die precies dit doen. U bent bijvoorbeeld misschien bekend met de http
module; dit is de module die u zult gebruiken om een webserver te maken. Dit eenvoudige voorbeeld laat zien hoe het op
methode van de EventEmitter
klas is onderdeel geworden van de http.Server
klasse:
var http = require ("http"); var server = http.createServer (); server.on ("request", functie (req, res) res.end ("this is the response");); server.listen (3000);
Als u dit fragment uitvoert, wacht het proces op een verzoek; je kan gaan naar http: // localhost: 3000
en je krijgt het antwoord. Wanneer de serverinstance het verzoek van uw browser ontvangt, wordt een a "verzoek"
evenement, een gebeurtenis die onze luisteraar zal ontvangen en waarop hij kan reageren.
Dus, hoe kunnen we gaan over het creëren van een klasse die erven van EventEmitter
? Het is eigenlijk niet zo moeilijk. We zullen een eenvoudig maken Gebruikers lijst
klasse, die gebruikersobjecten afhandelt. Dus in a userlist.js
bestand, we beginnen met dit:
var util = require ("util"); var EventEmitter = require ("events"). EventEmitter;
We hebben de util
module om te helpen met de overerving. Vervolgens hebben we een database nodig: in plaats van een echte database te gebruiken, gebruiken we alleen een object:
var id = 1; var database = gebruikers: [id: id ++, naam: "Joe Smith", bezetting: "ontwikkelaar", id: id ++, naam: "Jane Doe", bezetting: "data analist", id: id ++ , naam: "John Henry", beroep: "ontwerper"];
Nu kunnen we onze module eigenlijk maken. Als u niet vertrouwd bent met knoopmodules, dan is dit de manier waarop ze werken: elk JavaScript dat we in dit bestand schrijven, is standaard alleen leesbaar vanuit het bestand. Als we het onderdeel willen maken van de openbare API van de module, maken we er een eigenschap van module.exports
, of een geheel nieuw object of functie toewijzen aan module.exports
. Laten we dit doen:
function UserList () EventEmitter.call (this);
Dit is de constructorfunctie, maar het is niet uw gebruikelijke JavaScript-constructorfunctie. Wat we hier doen, is het gebruik van de telefoontje
methode op de EventEmitter
constructor om die methode op de nieuwe uit te voeren Gebruikers lijst
object (dat is deze
). Als we een andere initialisatie voor ons doel moeten doen, kunnen we dit binnen deze functie doen, maar dat is alles wat we nu doen.
Overname van de constructor is echter niet genoeg; we moeten ook het prototype erven. Dit is waar de util
module komt binnen.
util.inherits (UserList, EventEmitter);
Hiermee wordt alles toegevoegd wat er is EventEmitter.prototype
naar UserList.prototype
; nu, onze Gebruikers lijst
instanties hebben alle methoden van een EventEmitter
aanleg. Maar we willen er natuurlijk nog meer toevoegen. We voegen een toe opslaan
methode, om ons toe te staan nieuwe gebruikers toe te voegen.
UserList.prototype.save = function (obj) obj.id = id ++; database.users.push (obj); this.emit ("saved-user", obj); ;
Deze methode neemt een object om op te slaan naar onze "Databank"
: het voegt een toe ID kaart
en duwt het in de gebruikersarray. Vervolgens wordt de "Gered door de gebruiker"
gebeurtenis en geeft het object door als gegevens. Als dit een echte database zou zijn, zou het opslaan ervan waarschijnlijk een asynchrone taak zijn, wat betekent dat we met het opgeslagen record een callback moeten accepteren. Het alternatief hiervoor is om een evenement uit te zenden, terwijl we aan het doen zijn. Als we nu iets willen doen met het opgeslagen record, kunnen we gewoon naar het evenement luisteren. We doen dit meteen. Laten we gewoon afsluiten Gebruikers lijst
UserList.prototype.all = function () return database.users; ; module.exports = Gebruikerslijst;
Ik heb nog een methode toegevoegd: een eenvoudige methode die alle gebruikers retourneert. Vervolgens wijzen we toe Gebruikers lijst
naar module.exports
.
Laten we dit in gebruik zien; in een ander bestand, zeg maar test.js
. Voeg het volgende toe:
var UserList = require ("./ userlist"); var users = new UserList (); users.on ("saved-user", functie (gebruiker) console.log ("saved:" + user.name + "(" + user.id + ")");); users.save (name: "Jane Doe", bezetting: "manager"); users.save (name: "John Jacob", beroep: "ontwikkelaar");
Nadat we onze nieuwe module hebben vereist en er een instantie van hebben gemaakt, luisteren we naar de "Gered door de gebruiker"
evenement. Dan kunnen we doorgaan en een paar gebruikers redden. Wanneer we dit uitvoeren, ziet u dat we twee berichten ontvangen en de namen en id's van de records die we hebben opgeslagen, afdrukken.
opgeslagen: Jane Doe (4) opgeslagen: John Jacob (5)
Dit zou natuurlijk andersom kunnen werken: we zouden het kunnen gebruiken op
methode vanuit onze klas en de uitzenden
methode buiten, of zowel binnen als buiten. Maar dit is een goed voorbeeld van hoe het zou kunnen worden gedaan.
Dus dat is hoe Node is EventEmitter
klasse werkt. Hieronder vindt u koppelingen naar de knooppuntdocumentatie voor enkele dingen waarover we hebben gesproken.