De gebeurtenismodule van Node gebruiken

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 waarom

Dus, 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.


Gebruik makend van 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.


anders EventEmitter methoden

Er 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 Modules

Sinds 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.


Conclusie

Dus dat is hoe Node is EventEmitter klasse werkt. Hieronder vindt u koppelingen naar de knooppuntdocumentatie voor enkele dingen waarover we hebben gesproken.

  • Node Events Module
  • Node Util-module
  • Node HTTP Agent Source - Dit toont het overervingspatroon dat we gebruikten.