Bruke Node Event Event Module

Da jeg først hørte om Node.js, trodde jeg det var bare en JavaScript-implementering for serveren. Men det er faktisk mye mer: det kommer med en rekke innebygde funksjoner som du ikke får i nettleseren. En av disse funksjonene er Eventmodulen, som har EventEmitter klasse. Vi vil se på det i denne opplæringen.


EventEmitter: Hva og hvorfor

Så, hva gjør det egentlig EventEmitter klasse gjør? Enkelt sagt, det lar deg lytte etter "hendelser" og tilordne handlinger som skal løpe når disse hendelsene oppstår. Hvis du er kjent med front-end JavaScript, vil du vite om mus- og tastaturhendelser som oppstår ved visse brukerinteraksjoner. Disse er svært like, bortsett fra at vi kan sende hendelser på egen hånd, når vi vil, og ikke nødvendig ut fra brukerinteraksjon. Prinsippene EventEmitter er basert på har blitt kalt publiserings- / abonnementsmodellen, fordi vi kan abonnere på hendelser og deretter publisere dem. Det er mange front-end-biblioteker bygget med pub / sub-støtte, men Node har det bygget inn.

Det andre viktige spørsmålet er dette: Hvorfor skulle du bruke arrangementsmodellen? I Node er det et alternativ til dypt nestede tilbakeringinger. Mange Node-metoder kjøres asynkront, noe som betyr at å kjøre kode etter at metoden er ferdig, må du sende en tilbakeringingsmetode til funksjonen. Til slutt vil koden din se ut som en gigantratt. For å forhindre dette, avgir mange node klasser hendelser som du kan lytte til. Dette lar deg organisere koden din slik du vil, og ikke bruke tilbakeringinger.

En siste fordel for hendelser: de er en veldig løs måte å koble deler av koden sammen. En hendelse kan sendes ut, men hvis ingen kode lytter etter det, er det greit: det vil bare passere ubemerket. Dette betyr at fjernelse av lyttere (eller hendelsesutslipp) aldri resulterer i JavaScript-feil.


Ved hjelp av EventEmitter

Vi begynner med EventEmitter klasse på egen hånd. Det er ganske enkelt å komme seg til: vi krever bare hendelsesmodulen:

 var hendelser = krever ("hendelser");

Dette arrangementer objektet har en enkelt eiendom, som er den EventEmitter klassen selv. Så la oss lage et enkelt eksempel for startere:

 var EventEmitter = krever ("hendelser"). EventEmitter; var ee = ny EventEmitter (); ee.on ("someEvent", funksjon () console.log ("hendelsen har oppstått");); ee.emit ( "someEvent");

Vi begynner med å lage en ny EventEmitter gjenstand. Dette objektet har to hovedmetoder som vi bruker til hendelser: og avgir.

Vi begynner med . Denne metoden tar to parametere: Vi starter med navnet på arrangementet vi lytter etter: i dette tilfellet er det "SomeEvent". Men selvfølgelig kan det være noe, og du vil vanligvis velge noe bedre. Den andre parameteren er funksjonen som vil bli kalt når hendelsen oppstår. Det er alt som kreves for å sette opp et arrangement.

Nå, for å skyte hendelsen, passerer du hendelsesnavnet til EventEmitter eksempel er avgir metode. Det er den siste linjen i koden ovenfor. Hvis du kjører den koden, ser du at vi får teksten skrevet ut til konsollen.

Det er den mest grunnleggende bruken av en EventEmitter. Du kan også inkludere data ved avfyring av hendelser:

 ee.emit ("ny bruker", userObj);

Det er bare en dataparameter, men du kan inkludere så mange du vil. For å bruke dem i hendelseshåndteringsfunksjonen, ta dem bare som parametere:

 ee.on ("ny bruker", funksjon (data) // bruk data her);

Før du fortsetter, la meg klargjøre en del av EventEmitter funksjonalitet. Vi kan ha mer enn én lytter for hver hendelse; Flere hendelseslyttere kan tildeles (alle med ), og alle funksjoner vil bli kalt når hendelsen blir sparket. Som standard lar Node opptil ti lyttere på en hendelse samtidig; Hvis flere er opprettet, vil noden utstede en advarsel. Vi kan imidlertid endre dette beløpet ved å bruke setMaxListeners. Hvis du for eksempel kjører dette, bør du se en advarsel skrevet ut over utgangen:

 ee.on ("someEvent", funksjon () console.log ("event 1");); ee.on ("someEvent", funksjon () console.log ("event 2");); ee.on ("someEvent", funksjon () console.log ("event 3");); ee.on ("someEvent", funksjon () console.log ("event 4");); ee.on ("someEvent", funksjon () console.log ("event 5");); ee.on ("someEvent", funksjon () console.log ("event 6");); ee.on ("someEvent", funksjon () console.log ("event 7");); ee.on ("someEvent", funksjon () console.log ("event 8");); ee.on ("someEvent", funksjon () console.log ("event 9");); ee.on ("someEvent", funksjon () console.log ("event 10");); ee.on ("someEvent", funksjon () console.log ("event 11");); ee.emit ( "someEvent");

For å angi maksimalt antall seere, legg til denne linjen over lytterne:

 ee.setMaxListeners (20);

Nå når du kjører det, vil du ikke få en advarsel.


Annen EventEmitter metoder

Det er noen andre EventEmitter metoder du finner nyttig.

Her er en fin en: en gang. Det er akkurat som metode, bortsett fra at den bare virker en gang. Etter å ha blitt kalt for første gang, blir lytteren fjernet.

 ee.once ("firstConnection", funksjon () console.log ("Du vil aldri se dette igjen");;); ee.emit ( "firstConnection"); ee.emit ( "firstConnection");

Hvis du kjører dette, ser du bare meldingen en gang. Den andre emisjonen av arrangementet blir ikke hentet av noen lyttere (og det er greit, forresten), fordi en gang lytteren ble fjernet etter at den ble brukt en gang.

Når vi snakker om å fjerne lyttere, kan vi gjøre det selv, manuelt, på få måter. Først kan vi fjerne en enkelt lytter med removeListener metode. Det krever to parametre: hendelsesnavnet og lytterfunksjonen. Så langt har vi brukt anonyme funksjoner som våre lyttere. Hvis vi vil kunne fjerne en lytter senere, må den være en funksjon med et navn vi kan referere til. Vi kan bruke dette removeListener metode for å duplisere virkningene av en gang metode:

 funksjon onlyOnce () console.log ("Du vil aldri se dette igjen"); ee.removeListener ("firstConnection", onlyOnce);  ee.on ("firstConnection", onlyOnce) ee.emit ("firstConnection"); ee.emit ( "firstConnection");

Hvis du kjører dette, vil du se at det har samme effekt som en gang.

Hvis du vil fjerne alle lytterne bundet til en bestemt hendelse, kan du bruke removeAllListeners; bare send det navnet på arrangementet:

 ee.removeAllListeners ( "firstConnection");

For å fjerne alle lyttere for alle hendelser, ring funksjonen uten parametere.

ee.removeAllListeners ();

Det er en siste metode: lytteren. Denne metoden tar et hendelsesnavn som en parameter og returnerer en rekke av alle funksjonene som lytter for den hendelsen. Her er et eksempel på det, basert på vår bare én gang eksempel:

 funksjon 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");

Vi avslutter denne delen med en bit meta-ness. Våre EventEmitter Eksemplet i seg selv brenner to hendelser av seg selv, som vi kan lytte til: en når vi lager nye lyttere, og en når vi fjerner dem. Se her:

 ee.on ("newListener", funksjon (evtName, fn) console.log ("New Listener:" + evtName);); ee.on ("removeListener", funksjon (evtName) console.log ("Fjernet lytter:" + evtName);); funksjon foo ()  ee.on ("save-user", foo); ee.removeListener ("save-user", foo);

Når du kjører dette, ser du våre lyttere for både nye lyttere og fjernede lyttere har blitt kjørt, og vi får meldingene vi forventet.

Så, nå som vi har sett alle metodene som en EventEmitter eksempel har, la oss se hvordan det fungerer sammen med andre moduler.

EventEmitter Innvendige moduler

Siden EventEmitter klassen er bare vanlig JavaScript, det gir perfekt mening at den kan brukes i andre moduler. I dine egne JavaScript-moduler kan du opprette EventEmitter forekomster, og bruk dem til å håndtere interne hendelser. Det er enkelt, skjønt. Mer interessant, ville være å lage en modul som arver fra EventEmitter, slik at vi kan bruke sin funksjonalitet del av offentlig API.

Faktisk er det innebygde Node-moduler som gjør akkurat dette. For eksempel kan du være kjent med http modul; Dette er modulen du vil bruke til å lage en webserver. Dette grunnleggende eksemplet viser hvordan metode av EventEmitter klassen har blitt en del av http.Server klasse:

 var http = krever ("http"); var server = http.createServer (); server.on ("request", funksjon (req, res) res.end ("dette er svaret");); server.listen (3000);

Hvis du kjører denne koden, vil prosessen vente på en forespørsel; du kan gå til http: // localhost: 3000 og du får svaret. Når server-forekomsten mottar forespørselen fra nettleseren din, sender den ut en "be om" arrangement, en hendelse som vår lytter vil motta og kan handle på.

Så, hvordan kan vi gå om å skape en klasse som vil arve fra EventEmitter? Det er faktisk ikke så vanskelig. Vi lager en enkel Userlist klassen, som håndterer brukerobjekter. Så, i en userlist.js fil, vi starter med dette:

 var util = krever ("util"); var EventEmitter = krever ("hendelser"). EventEmitter;

Vi trenger util modul for å hjelpe med arvingen. Deretter trenger vi en database: i stedet for å bruke en faktisk database, skjønner vi bare et objekt:

 var id = 1; var-database = brukere: [id: id ++, navn: "Joe Smith", yrke: "developer", id: id ++, navn: "Jane Doe", yrke: "dataanalytiker", id: id ++ , navn: "John Henry", yrke: "designer"];

Nå kan vi faktisk lage vår modul. Hvis du ikke er kjent med Node-moduler, så fungerer det slik: Alle JavaScript vi skriver inn i denne filen, kan bare leses fra innsiden av filen som standard. Hvis vi vil gjøre det til en del av modulens offentlige API, gjør vi det til en eiendom module.exports, eller tilordne et helt nytt objekt eller en funksjon til module.exports. La oss gjøre dette:

 funksjon Brukerliste () EventEmitter.call (dette); 

Dette er konstruktørfunksjonen, men det er ikke din vanlige JavaScript-konstruktørfunksjon. Det vi gjør her bruker anrop metode på EventEmitter konstruktør å kjøre den metoden på den nye Userlist objekt (som er dette). Hvis vi trenger å gjøre noen andre initialiseringer til vårt objekt, kan vi gjøre det inne i denne funksjonen, men det er alt vi skal gjøre for nå.

Å arve konstruktøren er ikke nok skjønt; vi må også arve prototypen. Det er her util modulen kommer inn.

 util.inherits (UserList, EventEmitter);

Dette vil legge til alt som er på EventEmitter.prototype til UserList.prototype; nå, vår Userlist forekomster vil ha alle metodene til en EventEmitter forekomst. Men vi vil selvfølgelig legge til noe mer. Vi legger til en lagre metode, slik at vi kan legge til nye brukere.

 UserList.prototype.save = funksjon (obj) obj.id = id ++; database.users.push (obj); this.emit ("saved-user", obj); ;

Denne metoden tar et objekt å lagre i vår "Database": det legger til en id og skyver den inn i brukerlisten. Deretter sender den ut "Frelst brukere" hendelse, og sender objektet som data. Hvis dette var en ekte database, ville det trolig være en asynkron oppgave, slik at det var å jobbe med den lagrede posten vi måtte godta tilbakekalling. Alternativet til dette er å avgi en hendelse, som vi gjør. Nå, hvis vi vil gjøre noe med den lagrede posten, kan vi bare høre på hendelsen. Vi gjør dette om et sekund. La oss bare lukke opp Userlist

 UserList.prototype.all = function () return database.users; ; module.exports = UserList;

Jeg har lagt til en annen metode: en enkel som returnerer alle brukerne. Så tildeler vi Userlist til module.exports.

La oss se dette i bruk; i en annen fil, si test.js. Legg til følgende:

 var UserList = krever ("./ userlist"); var users = new UserList (); users.on ("saved-user", funksjon (bruker) console.log ("saved:" + user.name + "(" + user.id + ")");); users.save (navn: "Jane Doe", yrke: "manager"); users.save (navn: "John Jacob", yrke: "developer");

Etter å ha krevd vår nye modul og opprettet en forekomst av det, lytter vi etter "Frelst brukere" begivenhet. Så kan vi gå videre og lagre noen få brukere. Når vi kjører dette, ser vi at vi får to meldinger, skriver ut navnene og idsene til postene vi lagret.

 reddet: Jane Doe (4) reddet: John Jacob (5)

Selvfølgelig kan dette fungere på den andre siden: vi kunne bruke metode fra innsiden av vår klasse og avgir metode utenfor, eller både innvendig eller utvendig. Men dette er et godt eksempel på hvordan det kan gjøres.


Konklusjon

Så det er hvordan Node er EventEmitter klassearbeid. Nedenfor finner du koblinger til Node-dokumentasjonen for noen av tingene vi har snakket om.

  • Node Events Module
  • Node Util Module
  • Node HTTP Agent Source - Dette viser arvsmønsteret vi brukte.