Usando el módulo de eventos de Node

Cuando escuché por primera vez sobre Node.js, pensé que era solo una implementación de JavaScript para el servidor. Pero en realidad es mucho más: viene con una gran cantidad de funciones integradas que no se incluyen en el navegador. Una de esas funcionalidades es el módulo de eventos, que tiene la EventEmitter clase. Lo veremos en este tutorial..


EventEmitter: Qué y por qué

Entonces, ¿qué hace exactamente el EventEmitter clase hacer? En pocas palabras, le permite escuchar "eventos" y asignar acciones para ejecutar cuando se producen esos eventos. Si está familiarizado con el JavaScript de front-end, sabrá acerca de los eventos del mouse y el teclado que se producen en ciertas interacciones del usuario. Estos son muy similares, excepto que podemos emitir eventos por nuestra cuenta, cuando queremos, y no es necesario en función de la interacción del usuario. Los principios EventEmitter se basa en el llamado modelo de publicación / suscripción, porque podemos suscribirnos a eventos y luego publicarlos. Hay muchas bibliotecas de aplicaciones para el usuario creadas con soporte de pub / sub, pero Node lo tiene incorporado.

La otra pregunta importante es esta: ¿por qué usarías el modelo de evento? En Node, es una alternativa a los callbacks profundamente anidados. Una gran cantidad de métodos de Node se ejecutan de forma asíncrona, lo que significa que para ejecutar el código una vez que el método haya finalizado, debe pasar un método de devolución de llamada a la función. Eventualmente, su código se verá como un embudo gigante. Para evitar esto, muchas clases de nodos emiten eventos que puede escuchar. Esto le permite organizar su código de la manera que desea, y no usar devoluciones de llamada.

Un último beneficio de los eventos: son una forma muy suelta de unir partes de su código. Se puede emitir un evento, pero si ningún código lo está escuchando, está bien: simplemente pasará desapercibido. Esto significa que eliminar los oyentes (o las emisiones de eventos) nunca produce errores de JavaScript.


Utilizando EventEmitter

Comenzaremos con el EventEmitter clase por su cuenta Es bastante simple llegar: solo necesitamos el módulo de eventos:

 var events = require ("eventos");

Esta eventos objeto tiene una sola propiedad, que es la EventEmitter clase en si Entonces, vamos a hacer un ejemplo simple para empezar:

 var EventEmitter = require ("eventos"). EventEmitter; var ee = nuevo EventEmitter (); ee.on ("someEvent", function () console.log ("ha ocurrido un evento");); ee.emit ("someEvent");

Comenzamos creando una nueva EventEmitter objeto. Este objeto tiene dos métodos principales que usamos para eventos: en y emitir.

Empezamos con en. Este método toma dos parámetros: comenzamos con el nombre del evento que estamos escuchando: en este caso, eso es "algún evento". Pero, por supuesto, podría ser cualquier cosa, y normalmente elegirás algo mejor. El segundo parámetro es la función que se llamará cuando ocurra el evento. Eso es todo lo que se requiere para organizar un evento..

Ahora, para activar el evento, pasa el nombre del evento a la EventEmitter instancias emitir método. Esa es la última línea del código de arriba. Si ejecuta ese código, verá que imprimimos el texto en la consola..

Ese es el uso más básico de un EventEmitter. También puede incluir datos al disparar eventos:

 ee.emit ("nuevo usuario", userObj);

Eso es solo un parámetro de datos, pero puede incluir tantos como desee. Para usarlos en su función de controlador de eventos, simplemente tómelos como parámetros:

 ee.on ("nuevo usuario", función (datos) // usar datos aquí);

Antes de continuar, permítanme aclarar parte de la EventEmitter funcionalidad Podemos tener más de un oyente para cada evento; Se pueden asignar múltiples escuchas de eventos (todos con en), y todas las funciones serán llamadas cuando se dispare el evento. De forma predeterminada, Node permite hasta diez oyentes en un evento a la vez; Si se crean más, el nodo emitirá una advertencia. Sin embargo, podemos cambiar esta cantidad usando setMaxListeners. Por ejemplo, si ejecuta esto, debería ver una advertencia impresa sobre la salida:

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

Para establecer el número máximo de espectadores, agregue esta línea sobre los oyentes:

 ee.setMaxListeners (20);

Ahora, cuando lo ejecutes, no recibirás una advertencia..


Otro EventEmitter Métodos

Hay algunos otros EventEmitter métodos que encontrarás útiles.

Aquí hay uno limpio: una vez. Es como el en Método, excepto que solo funciona una vez. Después de ser llamado por primera vez, se elimina el oyente..

 ee.once ("firstConnection", function () console.log ("Nunca verás esto de nuevo");); ee.emit ("firstConnection"); ee.emit ("firstConnection");

Si ejecuta esto, solo verá el mensaje una vez. La segunda emisión del evento no es captada por ningún oyente (y eso está bien, por cierto), porque la una vez el oyente fue eliminado después de ser usado una vez.

Hablando de eliminar a los oyentes, podemos hacer esto nosotros mismos, manualmente, de varias maneras. Primero, podemos eliminar un solo oyente con el removeListener método. Toma dos parámetros: el nombre del evento y la función de escucha. Hasta ahora, hemos estado usando funciones anónimas como nuestros oyentes. Si queremos poder eliminar un oyente más tarde, será necesario que sea una función con un nombre al que podamos hacer referencia. Podemos usar esto removeListener Método para duplicar los efectos de la una vez método:

 function onlyOnce () console.log ("Nunca verás esto de nuevo"); ee.removeListener ("firstConnection", onlyOnce);  ee.on ("firstConnection", onlyOnce) ee.emit ("firstConnection"); ee.emit ("firstConnection");

Si ejecuta esto, verá que tiene el mismo efecto que una vez.

Si desea eliminar todos los escuchas vinculados a un evento determinado, puede utilizar removeAllListeners; solo pásale el nombre del evento:

 ee.removeAllListeners ("firstConnection");

Para eliminar todos los escuchas de todos los eventos, llame a la función sin ningún parámetro.

ee.removeAllListeners ();

Hay un último método: oyente. Este método toma un nombre de evento como parámetro y devuelve una matriz de todas las funciones que escuchan ese evento. Aquí hay un ejemplo de eso, basado en nuestra sólo una vez ejemplo:

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

Terminaremos esta sección con un poco de meta-ness. Nuestro EventEmitter La instancia en sí dispara dos eventos propios, que podemos escuchar: uno cuando creamos nuevos oyentes y uno cuando los eliminamos. Mira aquí:

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

Al ejecutar esto, verá que se han ejecutado nuestros escuchas, tanto para los nuevos oyentes como para los escuchados eliminados, y recibimos los mensajes que esperábamos..

Así que, ahora que hemos visto todos los métodos que una EventEmitter La instancia tiene, veamos cómo funciona en conjunto con otros módulos..

EventEmitter Módulos internos

Desde el EventEmitter clase es solo JavaScript regular, tiene mucho sentido que se puede usar dentro de otros módulos. Dentro de tus propios módulos de JavaScript, puedes crear EventEmitter instancias, y usarlas para manejar eventos internos. Eso es simple, sin embargo. Más interesante, sería crear un módulo que hereda de EventEmitter, Para que podamos usar su funcionalidad parte de la API pública..

En realidad, hay módulos Nodo integrados que hacen exactamente esto. Por ejemplo, usted puede estar familiarizado con el http módulo; Este es el módulo que utilizará para crear un servidor web. Este ejemplo básico muestra cómo el en método de la EventEmitter clase se ha convertido en parte de la servidor http clase:

 var http = require ("http"); var server = http.createServer (); server.on ("request", function (req, res) res.end ("esta es la respuesta");); server.listen (3000);

Si ejecuta este fragmento de código, el proceso esperará una solicitud; usted puede ir a http: // localhost: 3000 y obtendrá la respuesta. Cuando la instancia del servidor recibe la solicitud de su navegador, emite un "solicitud" evento, un evento que nuestro oyente recibirá y puede actuar sobre.

Entonces, ¿cómo podemos ir creando una clase que heredará de EventEmitter? En realidad no es tan difícil. Vamos a crear un simple Lista de usuarios clase, que maneja objetos de usuario. Entonces, en un userlist.js archivo, vamos a empezar con esto:

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

Necesitamos el util Módulo para ayudar con la herencia. Luego, necesitamos una base de datos: en lugar de usar una base de datos real, solo usaremos un objeto:

 ID de var = 1; var database = usuarios: [id: id ++, nombre: "Joe Smith", ocupación: "desarrollador", id: id ++, nombre: "Jane Doe", ocupación: "analista de datos", id: id ++ , nombre: "John Henry", ocupación: "diseñador"];

Ahora, podemos crear nuestro módulo. Si no está familiarizado con los módulos Node, así es como funcionan: cualquier JavaScript que escribamos dentro de este archivo solo se puede leer desde dentro del archivo, de forma predeterminada. Si queremos que sea parte de la API pública del módulo, lo hacemos propiedad de módulo.exportaciones, o asignar un nuevo objeto o función a módulo.exportaciones. Hagámoslo:

 function UserList () EventEmitter.call (this); 

Esta es la función de constructor, pero no es su función de constructor de JavaScript habitual. Lo que estamos haciendo aquí es usar el llamada método en el EventEmitter constructor para ejecutar ese método en el nuevo Lista de usuarios objeto (que es esta). Si necesitamos hacer cualquier otra inicialización a nuestro objeto, podríamos hacerlo dentro de esta función, pero eso es todo lo que haremos por ahora..

La herencia del constructor no es suficiente; También necesitamos heredar el prototipo. Aquí es donde el util el módulo entra.

 util.inherits (UserList, EventEmitter);

Esto agregará todo lo que está en EventEmitter.prototype a UserList.prototype; ahora, nuestro Lista de usuarios instancias tendrán todos los métodos de una EventEmitter ejemplo. Pero queremos añadir algo más, por supuesto. Añadiremos un salvar Método, para permitirnos agregar nuevos usuarios..

 UserList.prototype.save = function (obj) obj.id = id ++; database.users.push (obj); this.emit ("usuario-guardado", obj); ;

Este método lleva un objeto para guardar a nuestro "base de datos": añade un carné de identidad y lo empuja en la matriz de usuarios. Entonces, emite el "usuario guardado" evento, y pasa el objeto como datos. Si se tratara de una base de datos real, guardarla probablemente sería una tarea asíncrona, lo que significa que para trabajar con el registro guardado tendríamos que aceptar una devolución de llamada. La alternativa a esto es emitir un evento, como estamos haciendo. Ahora, si queremos hacer algo con el registro guardado, podemos escuchar el evento. Haremos esto en un segundo. Vamos a cerrar la Lista de usuarios

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

He añadido un método más: uno simple que devuelve a todos los usuarios. Entonces, asignamos Lista de usuarios a módulo.exportaciones.

Ahora, veamos esto en uso; en otro archivo, digamos test.js. Agregue lo siguiente:

 var UserList = require ("./ userlist"); var users = new UserList (); users.on ("usuario guardado", función (user) console.log ("guardado:" + user.name + "(" + user.id + ")");); users.save (name: "Jane Doe", ocupación: "manager"); users.save (nombre: "John Jacob", ocupación: "desarrollador");

Después de requerir nuestro nuevo módulo y crear una instancia de él, escuchamos el "usuario guardado" evento. Entonces, podemos seguir adelante y salvar algunos usuarios. Cuando ejecutemos esto, verás que recibimos dos mensajes, imprimiendo los nombres e identificaciones de los registros que guardamos.

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

Por supuesto, esto podría funcionar al revés: podríamos estar usando el en método desde dentro de nuestra clase y la emitir Método fuera, o ambos dentro o fuera. Pero este es un buen ejemplo de cómo podría hacerse..


Conclusión

Así es como Node's EventEmitter trabajos de clase A continuación encontrará enlaces a la documentación de Node para algunas de las cosas que hemos estado hablando..

  • Módulo de Eventos Nodo
  • Módulo Util de Nodo
  • Fuente HTTP Agent del nodo: muestra el patrón de herencia que usamos.