Utilizzando il modulo eventi del nodo

Quando ho sentito parlare di Node.js, ho pensato che fosse solo un'implementazione JavaScript per il server. Ma in realtà è molto di più: viene fornito con una serie di funzioni integrate che non si ottengono nel browser. Uno di questi bit di funzionalità è il modulo eventi, che ha il EventEmitter classe. Lo vedremo in questo tutorial.


EventEmitter: Cosa e perché

Quindi, cosa fa esattamente il EventEmitter la classe fa? In parole povere, ti consente di ascoltare "eventi" e assegnare azioni da eseguire quando si verificano tali eventi. Se hai familiarità con JavaScript front-end, saprai degli eventi del mouse e della tastiera che si verificano su determinate interazioni dell'utente. Questi sono molto simili, tranne per il fatto che possiamo emettere eventi da soli, quando vogliamo e non necessari in base all'interazione dell'utente. I principi EventEmitter è basato sul modello di pubblicazione / sottoscrizione, perché possiamo iscriversi agli eventi e quindi pubblicarli. Ci sono molte librerie front-end costruite con supporto pub / sub, ma Node ce l'ha dentro.

L'altra domanda importante è questa: perché dovresti usare il modello di evento? Nel nodo, è un'alternativa ai callback profondamente annidati. Molti metodi Node vengono eseguiti in modo asincrono, il che significa che per eseguire il codice dopo che il metodo è terminato, è necessario passare un metodo di callback alla funzione. Alla fine, il tuo codice sembrerà un gigantesco imbuto. Per evitare ciò, molte classi di nodi emettono eventi che è possibile ascoltare. Ciò ti consente di organizzare il codice nel modo desiderato e di non utilizzare i callback.

Un ultimo vantaggio per gli eventi: sono un modo molto sciolto di unire parti del codice insieme. Un evento può essere emesso, ma se nessun codice lo sta ascoltando, va bene: passerà inosservato. Ciò significa che la rimozione di ascoltatori (o emissioni di eventi) non ha mai comportato errori JavaScript.


utilizzando EventEmitter

Inizieremo con il EventEmitter classe a sé stante. È abbastanza semplice da ottenere: abbiamo solo bisogno del modulo eventi:

 var events = require ("eventi");

Questo eventi oggetto ha una singola proprietà, che è il EventEmitter classe stessa. Quindi, facciamo un semplice esempio per i principianti:

 var EventEmitter = require ("events"). EventEmitter; var ee = new EventEmitter (); ee.on ("someEvent", function () console.log ("evento si è verificato");); ee.emit ( "someEvent");

Iniziamo creando un nuovo EventEmitter oggetto. Questo oggetto ha due metodi principali che usiamo per gli eventi: sopra e emettere.

Iniziamo con sopra. Questo metodo richiede due parametri: iniziamo con il nome dell'evento che stiamo ascoltando: in questo caso, quello è "SomeEvent". Ma naturalmente, potrebbe essere qualsiasi cosa e di solito sceglierai qualcosa di meglio. Il secondo parametro è la funzione che verrà chiamata quando si verifica l'evento. Questo è tutto ciò che è necessario per la creazione di un evento.

Ora, per attivare l'evento, si passa il nome dell'evento al EventEmitter esempio di emettere metodo. Questa è l'ultima riga del codice sopra. Se esegui quel codice, vedrai che il testo verrà stampato sulla console.

Questo è l'uso più basilare di un EventEmitter. Puoi anche includere dati quando si attivano gli eventi:

 ee.emit ("new-user", userObj);

Questo è solo un parametro di dati, ma puoi includere tutti quelli che vuoi. Per usarli nella funzione del gestore di eventi, prendili come parametri:

 ee.on ("nuovo utente", funzione (dati) // usa i dati qui);

Prima di continuare, permettimi di chiarire parte del EventEmitter funzionalità. Possiamo avere più di un ascoltatore per ogni evento; possono essere assegnati più ascoltatori di eventi (tutti con sopra), e tutte le funzioni verranno chiamate quando viene attivato l'evento. Per impostazione predefinita, il nodo consente fino a dieci listener su un evento alla volta; se ne vengono creati altri, il nodo emetterà un avviso. Tuttavia, possiamo modificare questa quantità utilizzando setMaxListeners. Ad esempio, se lo esegui, dovresti vedere un avviso stampato sopra l'output:

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

Per impostare il numero massimo di spettatori, aggiungi questa riga sopra gli ascoltatori:

 ee.setMaxListeners (20);

Ora quando lo esegui, non riceverai un avviso.


Altro EventEmitter metodi

Ce ne sono alcuni altri EventEmitter metodi che troverai utili.

Ecco uno pulito: una volta. È proprio come il sopra metodo, tranne che funziona solo una volta. Dopo essere stato chiamato per la prima volta, l'ascoltatore viene rimosso.

 ee.once ("firstConnection", function () console.log ("Non lo vedrai mai più");); ee.emit ( "firstConnection"); ee.emit ( "firstConnection");

Se lo esegui, vedrai il messaggio solo una volta. La seconda emissione dell'evento non viene ripresa da nessun ascoltatore (e va bene, comunque), perché il una volta l'ascoltatore è stato rimosso dopo essere stato utilizzato una sola volta.

Parlando di rimuovere gli ascoltatori, possiamo farlo da soli, manualmente, in pochi modi. Innanzitutto, possiamo rimuovere un singolo listener con il removeListener metodo. Richiede due parametri: il nome dell'evento e la funzione listener. Finora, abbiamo usato funzioni anonime come nostri ascoltatori. Se vogliamo essere in grado di rimuovere un listener in seguito, dovrà essere una funzione con un nome a cui fare riferimento. Possiamo usare questo removeListener metodo per duplicare gli effetti del una volta metodo:

 function onlyOnce () console.log ("Non lo vedrai mai più"); ee.removeListener ("firstConnection", onlyOnce);  ee.on ("firstConnection", onlyOnce) ee.emit ("firstConnection"); ee.emit ( "firstConnection");

Se lo esegui, vedrai che ha lo stesso effetto di una volta.

Se si desidera rimuovere tutti gli ascoltatori associati a un determinato evento, è possibile utilizzare removeAllListeners; basta passargli il nome dell'evento:

 ee.removeAllListeners ( "firstConnection");

Per rimuovere tutti gli ascoltatori per tutti gli eventi, chiamare la funzione senza alcun parametro.

ee.removeAllListeners ();

C'è un ultimo metodo: ascoltatore. Questo metodo prende un nome evento come parametro e restituisce una matrice di tutte le funzioni che stanno ascoltando quell'evento. Ecco un esempio di questo, basato sul nostro solo una volta esempio:

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

Termineremo questa sezione con un po 'di meta-ness. Nostro EventEmitter l'istanza stessa lancia in effetti due eventi propri, che possiamo ascoltare: uno quando creiamo nuovi ascoltatori e uno quando li rimuoviamo. Vedere qui:

 ee.on ("newListener", function (evtName, fn) console.log ("Nuovo listener:" + evtName);); ee.on ("removeListener", function (evtName) console.log ("Listener rimosso:" + evtName);); function foo ()  ee.on ("salva-utente", foo); ee.removeListener ("salva-utente", foo);

Eseguendo questa operazione, vedrai i nostri ascoltatori sia per i nuovi ascoltatori che per gli ascoltatori rimossi che sono stati eseguiti e otteniamo i messaggi che ci aspettavamo.

Quindi, ora che abbiamo visto tutti i metodi che a EventEmitter l'istanza ha, vediamo come funziona in combinazione con altri moduli.

EventEmitter Moduli interni

Dal momento che il EventEmitter la classe è solo un normale JavaScript, ha perfettamente senso che possa essere utilizzata all'interno di altri moduli. All'interno dei tuoi moduli JavaScript, puoi creare EventEmitter istanze e usarli per gestire eventi interni. È semplice, però. Più interessante, sarebbe quello di creare un modulo che eredita da EventEmitter, quindi possiamo usare la sua funzionalità parte dell'API pubblica.

In realtà, ci sono moduli di nodo integrati che fanno esattamente questo. Ad esempio, potresti avere familiarità con http modulo; questo è il modulo che userai per creare un server web. Questo esempio di base mostra come sopra metodo del EventEmitter la classe è diventata parte del http.Server classe:

 var http = require ("http"); var server = http.createServer (); server.on ("request", function (req, res) res.end ("questa è la risposta");); server.listen (3000);

Se si esegue questo snippet, il processo attenderà una richiesta; Puoi andare a http: // localhost: 3000 e avrai la risposta. Quando l'istanza del server riceve la richiesta dal tuo browser, emette a "richiesta" evento, un evento che il nostro ascoltatore riceverà e potrà agire.

Quindi, come possiamo creare una classe da cui erediteremo EventEmitter? In realtà non è così difficile. Creeremo un semplice Lista degli utenti classe, che gestisce gli oggetti utente. Quindi, in a userlist.js file, inizieremo con questo:

 var util = require ("util"); var EventEmitter = require ("events"). EventEmitter;

Abbiamo bisogno del util modulo per aiutare con l'ereditare. Successivamente, abbiamo bisogno di un database: invece di usare un vero database, useremo solo un oggetto:

 var id = 1; var database = utenti: [id: id ++, nome: "Joe Smith", occupazione: "sviluppatore", id: id ++, nome: "Jane Doe", occupazione: "analista di dati", id: id ++ , nome: "John Henry", occupazione: "designer"];

Ora possiamo effettivamente creare il nostro modulo. Se non hai familiarità con i moduli del nodo, ecco come funzionano: qualsiasi JavaScript che scriviamo all'interno di questo file è leggibile solo all'interno del file, per impostazione predefinita. Se vogliamo renderlo parte dell'API pubblica del modulo, ne facciamo una proprietà module.exports, o assegnare un intero nuovo oggetto o funzione a module.exports. Facciamolo:

 function UserList () EventEmitter.call (this); 

Questa è la funzione di costruzione, ma non è la solita funzione del costruttore JavaScript. Quello che stiamo facendo qui sta usando il chiamata metodo sul EventEmitter costruttore per eseguire quel metodo sul nuovo Lista degli utenti oggetto (che è Questo). Se dovessimo eseguire qualsiasi altra inizializzazione sul nostro oggetto, potremmo farlo all'interno di questa funzione, ma è tutto ciò che faremo per ora.

Tuttavia, ereditare il costruttore non è sufficiente; abbiamo anche bisogno di ereditare il prototipo. Questo è dove il util il modulo entra.

 util.inherits (UserList, EventEmitter);

Questo aggiungerà tutto ciò che è acceso EventEmitter.prototype a UserList.prototype; ora, nostro Lista degli utenti le istanze avranno tutti i metodi di un EventEmitter esempio. Ma vogliamo aggiungerne ancora, naturalmente. Aggiungeremo un salvare metodo, per permetterci di aggiungere nuovi utenti.

 UserList.prototype.save = function (obj) obj.id = id ++; database.users.push (obj); this.emit ("utente salvato", obj); ;

Questo metodo prende un oggetto da salvare sul nostro "Banca dati": aggiunge un id e lo spinge nell'array degli utenti. Quindi, emette il "Salvato-utente" evento e passa l'oggetto come dati. Se si trattasse di un vero database, il salvataggio sarebbe probabilmente un'attività asincrona, il che significa che per lavorare con il record salvato dovremmo accettare una richiamata. L'alternativa a questo è emettere un evento, come stiamo facendo. Ora, se vogliamo fare qualcosa con il record salvato, possiamo semplicemente ascoltare l'evento. Lo faremo in un secondo. Chiudiamo il Lista degli utenti

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

Ho aggiunto un altro metodo: uno semplice che restituisce tutti gli utenti. Quindi, assegniamo Lista degli utenti a module.exports.

Ora, vediamo questo in uso; in un altro file, ad esempio test.js. Aggiungi il seguente:

 var UserList = require ("./ userlist"); var users = new UserList (); users.on ("utente salvato", funzione (utente) console.log ("salvato:" + user.name + "(" + user.id + ")");); users.save (name: "Jane Doe", occupazione: "manager"); users.save (nome: "John Jacob", occupazione: "sviluppatore");

Dopo aver richiesto il nostro nuovo modulo e aver creato un'istanza di esso, ascoltiamo il "Salvato-utente" evento. Quindi, possiamo andare avanti e salvare alcuni utenti. Quando eseguiremo questa operazione, vedremo che riceviamo due messaggi, stampando i nomi e gli ID dei record che abbiamo salvato.

 salvato: Jane Doe (4) ha salvato: John Jacob (5)

Naturalmente, questo potrebbe funzionare in senso inverso: potremmo usare il sopra metodo da dentro la nostra classe e il emettere metodo esterno o interno o esterno. Ma questo è un buon esempio di come potrebbe essere fatto.


Conclusione

Ecco come è Node EventEmitter lavori di classe. Di seguito troverai i link alla documentazione del nodo per alcune delle cose di cui abbiamo parlato.

  • Modulo Eventi nodo
  • Node Util Module
  • Nodo Origine agente HTTP: mostra il modello di ereditarietà utilizzato.