Node.js EventEmitter
Todas las operaciones asíncronas de E/S en Node.js envían un evento a la cola de eventos cuando se completan.
Muchos objetos en Node.js distribuyen eventos: un objeto net.Server emite un evento cada vez que hay una nueva conexión, un objeto fs.readStream emite un evento cuando se abre un archivo. Todos estos objetos que generan eventos son instancias de events.EventEmitter.
EventEmitter es el módulo central en Node.js utilizado para crear, registrar y disparar eventos.
EventEmitter es la base de la programación orientada a eventos y ayuda a los desarrolladores a implementar fácilmente el mecanismo de publicación y suscripción de eventos.
Clase EventEmitter
El módulo events solo proporciona un objeto: events.EventEmitter.
El núcleo de EventEmitter es la encapsulación de la activación de eventos y las funciones de los listeners de eventos.
Puedes acceder a este módulo medianterequire("events");para acceder a este módulo.
Ejemplo
var events = require('events');
// Crear el objeto eventEmitter
var eventEmitter = new events.EventEmitter();
Si se produce un error al instanciar el objeto EventEmitter, se disparará el evento error. Cuando se añade un nuevo listener, se activa el evento newListener; cuando se elimina un listener, se activa el evento removeListener.
A continuación usamos un ejemplo sencillo para explicar el uso de EventEmitter:
Ejemplo
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('Se activó el evento some_event');
});
setTimeout(function() {
event.emit('some_event');
}, 1000);
Al ejecutar este código, después de 1 segundo la consola mostrarásome_event disparador de eventoEl principio es que el objeto event registra un listener para el evento some_event, luego, mediante setTimeout, después de 1000 milisegundos se envía el evento some_event al objeto event, momento en el cual se llama al listener de some_event.
El resultado de la ejecución es el siguiente:
$ node event.js some_event 事件触发
Cada evento de EventEmitter se compone de un nombre de evento y varios parámetros. El nombre del evento es una cadena que suele expresar un determinado significado semántico. Para cada evento, EventEmitter admite varios listeners de eventos.
Cuando se dispara un evento, los listeners registrados para ese evento se invocan de forma secuencial, y los parámetros del evento se pasan como argumentos de las funciones de callback.
Expliquemos este proceso con el siguiente ejemplo:
Ejemplo
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener1', arg1, arg2);
});
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener2', arg1, arg2);
});
emitter.emit('someEvent', 'Parámetro arg1', 'Parámetro arg2');
Al ejecutar el código anterior, el resultado de la ejecución es el siguiente:
$ node event.js listener1 arg1 参数 arg2 参数 listener2 arg1 参数 arg2 参数
En el ejemplo anterior, emitter registró dos listeners para el evento someEvent y luego disparó el evento someEvent.
En el resultado de la ejecución se puede observar que las funciones de callback de los dos listeners se llaman una tras otra. Este es el uso más sencillo de EventEmitter.
EventEmitter proporciona múltiples propiedades, comoonyemit。onla función se usa para vincular funciones de evento,emitla propiedad se usa para disparar un evento. A continuación, veamos en detalle la introducción a las propiedades de EventEmitter.
Métodos
| N.º | Método y descripción |
|---|---|
| 1 | addListener(event, listener) Añade un listener al final de la matriz de listeners para el evento especificado. |
| 2 | on(event, listener) Registra un listener para el evento especificado; acepta una cadena event y una función de callback.
server.on('connection', function (stream) {
console.log('someone connected!');
});
|
| 3 | once(event, listener) Registra un listener de una sola vez para el evento especificado, es decir, el listener solo puede dispararse una vez y se elimina inmediatamente después de dispararse.
server.once('connection', function (stream) {
console.log('Ah, we have our first user!');
});
|
| 4 | removeListener(event, listener) Elimina un listener específico del evento especificado; el listener debe ser uno que ya haya sido registrado para ese evento. Acepta dos parámetros: el primero es el nombre del evento y el segundo es el nombre de la función de callback.
var callback = function(stream) {
console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);
|
| 5 | removeAllListeners([event]) Elimina todos los listeners de todos los eventos; si se especifica un evento, elimina todos los listeners de ese evento. |
| 6 | setMaxListeners(n) De forma predeterminada, si agregas más de 10 listeners, EventEmitters mostrará un mensaje de advertencia. La función setMaxListeners se usa para cambiar el límite predeterminado del número de listeners. |
| 7 | listeners(event) Devuelve la matriz de listeners del evento especificado. |
| 8 | emit(event, [arg1], [arg2], [...]) Ejecuta cada listener en el orden de los listeners; si el evento tiene listeners registrados, devuelve true; de lo contrario, devuelve false. |
Métodos de clase
| N.º | Método y descripción |
|---|---|
| 1 | listenerCount(emitter, event) Devuelve el número de listeners del evento especificado. |
events.EventEmitter.listenerCount(emitter, eventName) //已废弃,不推荐 events.emitter.listenerCount(eventName) //推荐
Registrar un listener de evento:
Ejemplo
const myEmitter = new EventEmitter();
// Registrar un listener de evento
myEmitter.on('sayHello', (name) => {
console.log(`Hello, ${name}!`);
});
// Disparar el evento
myEmitter.emit('sayHello', 'Alice');
Salida:
Hello, Alice!
Usar once() para registrar un evento de una sola vez:
myEmitter.once('init', () => {
console.log('Initialization event occurred');
});
myEmitter.emit('init'); // 打印: Initialization event occurred
myEmitter.emit('init'); // 不会再触发
Al disparar el evento, se pueden pasar parámetros para que los use el listener:
Ejemplo
myEmitter.on('data', (value1, value2) => {
console.log(`Received values: ${value1}, ${value2}`);
});
myEmitter.emit('data', 'Node.js', 'EventEmitter');
// Salida: Received values: Node.js, EventEmitter
Si el evento disparado no tiene un listener correspondiente, EventEmitter lanzará un error:
Ejemplo
console.error('Error event triggered:', err);
});
myEmitter.emit('error', new Error('Something went wrong'));
// Imprime: Error event triggered: Error: Something went wrong
Eventos
| N.º | Evento y descripción |
|---|---|
| 1 | newListener
Este evento se dispara cuando se añade un nuevo listener. |
| 2 | removeListener
Elimina un listener de la matriz de listeners especificada. Ten en cuenta que esta operación cambiará los índices de los listeners que están después del listener eliminado. |
Ejemplo
El siguiente ejemplo demuestra la aplicación de la clase EventEmitter mediante el evento connection (conexión).
Crea el archivo main.js, con el siguiente código:
Ejemplo
var eventEmitter = new events.EventEmitter();
// Listener n.º 1
var listener1 = function listener1() {
console.log('Se ejecutó el listener listener1.');
}
// Listener n.º 2
var listener2 = function listener2() {
console.log('Se ejecutó el listener listener2.');
}
// Vincular el evento connection, con la función de manejo listener1
eventEmitter.addListener('connection', listener1);
// Vincular el evento connection, con la función de manejo listener2
eventEmitter.on('connection', listener2);
var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " listeners escuchando el evento de conexión.");
// Manejar el evento connection
eventEmitter.emit('connection');
// Eliminar la función listener1 vinculada
eventEmitter.removeListener('connection', listener1);
console.log("listener1 ya no está siendo escuchado.");
// Disparar el evento de conexión
eventEmitter.emit('connection');
eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " listeners escuchando el evento de conexión.");
console.log("El programa ha terminado.");
El resultado de ejecución del código anterior es el siguiente:
$ node main.js 2 个监听器监听连接事件。 监听器 listener1 执行。 监听器 listener2 执行。 listener1 不再受监听。 监听器 listener2 执行。 1 个监听器监听连接事件。 程序执行完毕。
Evento error
EventEmitter define un evento especial llamado error, que contiene la semántica del error. Cuando encontramos una excepción, generalmente disparamos el evento error.
Cuando se dispara error, EventEmitter estipula que, si no hay un listener correspondiente, Node.js lo tratará como una excepción, saldrá del programa y mostrará un mensaje de error.
Generalmente debemos configurar un listener para los objetos que puedan disparar el evento error, para evitar que todo el programa se bloquee tras encontrar un error. Por ejemplo:
var events = require('events');
var emitter = new events.EventEmitter();
emitter.emit('error');
Al ejecutarlo se mostrará el siguiente error:
node.js:201 throw e; // process.nextTick error, or 'error' event on first tick ^ Error: Uncaught, unspecified 'error' event. at EventEmitter.emit (events.js:50:15) at Object.<anonymous> (/home/byvoid/error.js:5:9) at Module._compile (module.js:441:26) at Object..js (module.js:459:10) at Module.load (module.js:348:31) at Function._load (module.js:308:12) at Array.0 (module.js:479:10) at EventEmitter._tickCallback (node.js:192:40)
Heredar de EventEmitter
La mayoría de las veces no usamos EventEmitter directamente, sino que lo heredamos en los objetos. Todos los módulos centrales que admiten la respuesta a eventos, incluidos fs, net y http, son subclases de EventEmitter.
¿Por qué hacer esto? Hay dos razones:
-
Primero, la implementación de eventos en objetos con funcionalidad de entidad específica es semánticamente apropiada; la escucha y la ocurrencia de eventos deberían ser métodos de un objeto.
-
En segundo lugar, el mecanismo de objetos de JavaScript se basa en prototipos y admite cierta herencia múltiple parcial; heredar de EventEmitter no altera la relación de herencia original del objeto.
La mayoría de los módulos principales de Node.js (como HTTP y el sistema de archivos) heredan de EventEmitter; puedes crear tus propias clases para heredar de EventEmitter.
Ejemplo
const customEmitter = new MyEmitter();
customEmitter.on('customEvent', () => {
console.log('Custom event fired');
});
customEmitter.emit('customEvent');