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 hvorforSå, 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.
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: på
og avgir
.
Vi begynner med på
. 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 på
), 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.
EventEmitter
metoderDet er noen andre EventEmitter
metoder du finner nyttig.
Her er en fin en: en gang
. Det er akkurat som på
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 modulerSiden 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 på
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 på
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.
Så det er hvordan Node er EventEmitter
klassearbeid. Nedenfor finner du koblinger til Node-dokumentasjonen for noen av tingene vi har snakket om.