När jag först hörde om Node.js trodde jag att det bara var en JavaScript-implementering för servern. Men det är faktiskt mycket mer: det kommer med en mängd inbyggda funktioner som du inte får i webbläsaren. En av dessa funktioner är händelsemodulen, som har EventEmitter
klass. Vi tittar på det i den här handledningen.
EventEmitter
: Vad och varförSå vad gör exakt EventEmitter
klass gör? Enkelt sagt, det låter dig lyssna på "händelser" och tilldela åtgärder att köra när dessa händelser inträffar. Om du är bekant med front-end JavaScript får du veta om mus- och tangentbordshändelser som uppstår vid vissa användarinteraktioner. Dessa är väldigt lika, förutom att vi kan avge händelser på egen hand, när vi vill, och inte nödvändigt utifrån användarens interaktion. Principerna EventEmitter
baseras på har kallats publicera / prenumerera modellen, eftersom vi kan prenumerera på händelser och sedan publicera dem. Det finns många front-end-bibliotek byggda med pub / sub support, men Node har det inbyggt.
Den andra viktiga frågan är detta: varför skulle du använda händelsemodellen? I Node är det ett alternativ till djupt nestade callbacks. Många Node-metoder körs asynkront, vilket innebär att köra kod efter att metoden är klar måste du skicka en återkallningsmetod till funktionen. Så småningom kommer din kod att se ut som en jättektratt. För att förhindra detta avger många nodklasser händelser som du kan lyssna på. Detta gör att du kan organisera din kod så som du vill, och inte använda återuppringningar.
En sista fördel för händelser: De är ett väldigt löst sätt att koppla delar av din kod tillsammans. En händelse kan emitteras, men om ingen kod lyssnar på det, så är det okej: det kommer bara gått obemärkt. Det innebär att avlägsna lyssnare (eller händelseutsläpp) aldrig resulterar i JavaScript-fel.
EventEmitter
Vi börjar med EventEmitter
klass på egen hand. Det är ganska enkelt att komma till: vi behöver bara händelsemodulen:
var händelser = kräver ("händelser");
Detta evenemang
objektet har en enda egendom, vilket är EventEmitter
klassen själv. Så, låt oss göra ett enkelt exempel för nybörjare:
var EventEmitter = kräver ("händelser"). EventEmitter; var ee = ny EventEmitter (); ee.on ("someEvent", funktion () console.log ("händelse har uppstått");); ee.emit ( "someEvent");
Vi börjar med att skapa en ny EventEmitter
objekt. Detta objekt har två huvudmetoder som vi använder för händelser: på
och avge
.
Vi börjar med på
. Denna metod tar två parametrar: Vi börjar med namnet på det evenemang vi lyssnar på: i det här fallet är det "SomeEvent"
. Men det kan naturligtvis vara något, och du brukar välja något bättre. Den andra parametern är den funktion som kommer att ringas när händelsen inträffar. Det är allt som krävs för att skapa en händelse.
Nu, för att avfyra händelsen, skickar du händelsens namn till EventEmitter
instanser avge
metod. Det är den sista raden i koden ovan. Om du kör den koden ser du att texten skrivs ut till konsolen.
Det är den mest grundläggande användningen av en EventEmitter
. Du kan också inkludera data vid avfyra händelser:
ee.emit ("new-user", userObj);
Det är bara en dataparameter, men du kan inkludera så många du vill ha. För att använda dem i din händelsehanteringsfunktion, ta bara dem som parametrar:
ee.on ("nyanvändare", funktion (data) // använd data här);
Innan jag fortsätter, låt mig förtydliga en del av EventEmitter
funktionalitet. Vi kan ha mer än en lyssnare för varje händelse; flera händelse lyssnare kan tilldelas (alla med på
), och alla funktioner kommer att ringas när händelsen är avfyrade. Som standard tillåter Node upp till tio lyssnare på en händelse samtidigt. Om fler skapas, kommer noden att utfärda en varning. Vi kan dock ändra detta belopp med hjälp av setMaxListeners
. Om du till exempel kör detta bör du se en varning som skrivs ut ovanför utmatningen:
ee.on ("someEvent", funktion () console.log ("event 1");); ee.on ("someEvent", funktion () console.log ("händelse 2");); ee.on ("someEvent", funktion () console.log ("event 3");); ee.on ("someEvent", funktion () console.log ("event 4");); ee.on ("someEvent", funktion () console.log ("event 5");); ee.on ("someEvent", funktion () console.log ("event 6");); ee.on ("someEvent", funktion () console.log ("event 7");); ee.on ("someEvent", funktion () console.log ("händelse 8");); ee.on ("someEvent", funktion () console.log ("händelse 9");); ee.on ("someEvent", funktion () console.log ("händelse 10");); ee.on ("someEvent", funktion () console.log ("händelse 11");); ee.emit ( "someEvent");
För att ställa in det maximala antalet tittare lägger du till den här raden ovanför lyssnarna:
ee.setMaxListeners (20);
Nu när du kör det, får du inte en varning.
EventEmitter
metoderDet finns några andra EventEmitter
metoder du hittar användbara.
Här är en snygg en: en gång
. Det är precis som på
metod, förutom att det bara fungerar en gång. Efter att ha blivit kallad för första gången tas lyssnaren bort.
ee.once ("firstConnection", funktion () console.log ("Du kommer aldrig se det här igen");;); ee.emit ( "firstConnection"); ee.emit ( "firstConnection");
Om du kör det här ser du bara meddelandet en gång. Den andra utgåvan av händelsen hämtas inte av några lyssnare (och det är okej, förresten), för att en gång
lyssnaren togs bort efter att ha använts en gång.
När vi talar om att ta bort lyssnare kan vi göra det här manuellt, på några sätt. Först kan vi ta bort en enda lyssnare med removeListener
metod. Det tar två parametrar: händelsens namn och lyssnarfunktionen. Hittills har vi använt anonyma funktioner som våra lyssnare. Om vi vill kunna ta bort en lyssnare senare behöver den vara en funktion med ett namn som vi kan referera till. Vi kan använda detta removeListener
Metod för att duplicera effekterna av en gång
metod:
funktion onlyOnce () console.log ("Du kommer aldrig se det här igen"); ee.removeListener ("firstConnection", onlyOnce); ee.on ("firstConnection", onlyOnce) ee.emit ("firstConnection"); ee.emit ( "firstConnection");
Om du kör detta ser du att det har samma effekt som en gång
.
Om du vill ta bort alla lyssnare som är bundna till en viss händelse kan du använda removeAllListeners
; bara skicka det namnet på händelsen:
ee.removeAllListeners ( "firstConnection");
För att ta bort alla lyssnare för alla händelser, ring funktionen utan några parametrar.
ee.removeAllListeners ();
Det finns en sista metod: lyssnare
. Denna metod tar ett händelse namn som en parameter och returnerar en rad av alla funktioner som lyssnar för den händelsen. Här är ett exempel på det, baserat på vårt bara en gång
exempel:
funktion 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 avslutar det här avsnittet med en bit meta-ness. Vår EventEmitter
Förekomsten av sig själv bränder faktiskt två händelser som vi kan lyssna på: en när vi skapar nya lyssnare och en när vi tar bort dem. Kolla här:
ee.on ("newListener", funktion (evtName, fn) console.log ("New Listener:" + evtName);); ee.on ("removeListener", funktion (evtName) console.log ("Removed Listener:" + evtName);); funktion foo () ee.on ("spara-användare", foo); ee.removeListener ("spara-användare", foo);
När du kör det här ser du våra lyssnare för både nya lyssnare och borttagna lyssnare har körts och vi får de meddelanden som vi förväntade oss.
Så nu när vi har sett alla metoder som en EventEmitter
Instans har, låt oss se hur det fungerar tillsammans med andra moduler.
EventEmitter
Invändiga modulerSedan EventEmitter
klassen är bara vanlig javascript, det är perfekt att det kan användas inom andra moduler. Inne i dina egna JavaScript-moduler kan du skapa EventEmitter
instanser och använda dem för att hantera interna händelser. Det är dock enkelt. Intressantare skulle vara att skapa en modul som ärver från EventEmitter
, så vi kan använda sin funktionalitet del av det offentliga API.
Faktum är att det finns inbyggda nodmoduler som gör exakt detta. Du kan till exempel vara bekant med http
modul; Det här är den modul som du ska använda för att skapa en webbserver. Detta grundläggande exempel visar hur på
metod för EventEmitter
klassen har blivit en del av http.Server
klass:
var http = kräver ("http"); var server = http.createServer (); server.on ("request", funktion (req, res) res.end ("detta är svaret");); server.listen (3000);
Om du kör det här koden, väntar processen på en förfrågan. du kan gå till http: // localhost: 3000
och du får svaret. När serverns förekomst får begäran från din webbläsare, avger den en "begäran"
händelse, en händelse som vår lyssnare kommer att ta emot och kan agera på.
Så hur kan vi gå om att skapa en klass som kommer att arva från EventEmitter
? Det är faktiskt inte så svårt. Vi ska skapa en enkel Userlist
klass, som hanterar användarobjekt. Så, i en userlist.js
filen börjar vi med det här:
var util = kräver ("util"); var EventEmitter = kräver ("händelser"). EventEmitter;
Vi behöver util
modul för att hjälpa till med arvet. Därefter behöver vi en databas: istället för att använda en faktisk databas, använder vi bara ett objekt:
var id = 1; var: id: id ++, namn: "Jane Doe", yrke: "data analytiker", id: id ++ , namn: "John Henry", ockupation: "designer"];
Nu kan vi faktiskt skapa vår modul. Om du inte känner till Node-moduler, så fungerar det här: Alla JavaScript som vi skriver inuti den här filen är som standard endast läsbar från insidan av filen. Om vi vill göra det till en del av modulens offentliga API, gör vi det till en egenskap av module.exports
, eller tilldela ett helt nytt objekt eller en funktion till module.exports
. Nu gör vi det:
funktion UserList () EventEmitter.call (this);
Det här är konstruktörfunktionen, men det är inte din vanliga JavaScript-konstruktörsfunktion. Vad vi gör här använder ring upp
metod på EventEmitter
konstruktör att köra den metoden på det nya Userlist
objekt (vilket är detta
). Om vi behöver göra någon annan initialisering till vårt objekt, kan vi göra det inom denna funktion, men det är allt vi gör för nu.
Att erhålla konstruktören är inte tillräckligt men; vi måste också ärva prototypen. Det är här util
modulen kommer in.
util.inherits (UserList, EventEmitter);
Detta kommer att lägga till allt som är på EventEmitter.prototype
till UserList.prototype
; nu, vår Userlist
instanser kommer att ha alla metoder för en EventEmitter
exempel. Men vi vill naturligtvis lägga till lite mer. Vi lägger till en spara
metod, så att vi kan lägga till nya användare.
UserList.prototype.save = funktion (obj) obj.id = id ++; database.users.push (obj); this.emit ("saved-user", obj); ;
Den här metoden tar ett objekt att spara till vårt "databas"
: det lägger till en id
och trycker den in i användaruppsättningen. Sedan avger den "Räddade-user"
händelse och skickar objektet som data. Om det här var en riktig databas, skulle det vara en asynkron uppgift, vilket skulle innebära att det skulle fungera med den sparade posten vi skulle behöva acceptera en återuppringning. Alternativet till detta är att avge en händelse, som vi gör. Nu, om vi vill göra något med den sparade skivan, kan vi bara lyssna på evenemanget. Vi gör det på en sekund. Låt oss bara stänga upp Userlist
UserList.prototype.all = function () return database.users; ; module.exports = UserList;
Jag har lagt till ytterligare en metod: en enkel som returnerar alla användare. Sedan tilldelar vi Userlist
till module.exports
.
Nu, låt oss se detta i bruk; i en annan fil, säg test.js
. Lägg till följande:
var UserList = kräver ("./ användarlista"); var users = new UserList (); users.on ("saved-user", funktion (användare) console.log ("sparade:" + användarnamn + "(" + user.id + ")");); users.save (namn: "Jane Doe", yrke: "manager"); users.save (namn: "John Jacob", yrke: "developer");
Efter att ha krävt vår nya modul och skapat en förekomst av det lyssnar vi på "Räddade-user"
händelse. Då kan vi fortsätta och spara några användare. När vi kör det här ser du att vi får två meddelanden, skriver ut namnen och idsna på de poster vi sparade.
sparade: Jane Doe (4) sparade: John Jacob (5)
Det kan naturligtvis fungera tvärtom: vi skulle kunna använda på
metod från inuti vår klass och avge
metod utanför, eller både inifrån eller ut. Men det här är ett bra exempel på hur det skulle kunna göras.
Så det är hur Node är EventEmitter
klassarbeten. Nedan hittar du länkar till noddokumentationen för några av de saker vi pratat om.