Node.js EventEmitter 理解与使用

本文介绍了Node.js中EventEmitter类的基本概念、使用方法及其核心属性。探讨了如何注册事件监听器、触发事件以及常见的EventEmitter方法。同时,还讲解了error事件的重要性以及如何通过继承EventEmitter来构建自定义事件系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. EventEmitter是什么?

  • Node.js 的每个API都是异步的,并作为一个独立线程运行,使用异步函数调用。基本所有的事件机制都是用设计模式中的观察者模式实现。
  • Node.js中有多个内置事件,可以通过引入events模块,并通过实例化EventEmitter类来绑定和监听事件
  • Node.js里面的许多对象都会分发事件:一个net.Server对象会在每次有新连接时分发一个事件, 一个fs.readStream对象会在文件被打开的时候发出一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例

2. 使用EventEmitter类注册事件监听器

  • events 模块只提供了一个对象: events.EventEmitter其核心就是事件触发与事件监听功能的封装。
  • 创建EventEmitter对象:
var events = require('events');  // 引入 events 模块
var eventEmitter = new events.EventEmitter();  // 创建 eventEmitter 对象
  • 事件绑定及事件触发:EventEmitter 提供了多个属性,如 on 和 emit。on 函数用于绑定事件函数,emit 属性用于触发一个事件
eventEmitter.on('eventName', eventHandler);  // 绑定事件处理程序
eventEmitter.emit('eventName');  // 触发事件
  • 创建main.js文件,代码如下:
var events = require('events');       // 引入 events 模块
var eventEmitter = new events.EventEmitter();   // 创建 eventEmitter 对象

var connectHandler = function connected() {   // 创建事件处理程序
   console.log('连接成功。');
   eventEmitter.emit('data_received');  // 触发 data_received 事件 
}

eventEmitter.on('connection', connectHandler);  // 绑定 connection 事件处理程序

eventEmitter.on('data_received', function(){  // 使用匿名函数绑定 data_received 事件
   console.log('数据接收成功。');
});

eventEmitter.emit('connection');  // 触发 connection 事件  
console.log("程序执行完毕。");
  • 上面代码的运行结果为:
$ node main.js
连接成功。
数据接收成功。
程序执行完毕。
  • EventEmitter 的每个事件由一个事件名和若干参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持若干个事件监听器。当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
//event.js 文件
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', 'arg1 参数', 'arg2 参数'); 
  • 执行以上代码,运行的结果如下:
$ node event.js 
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数
  • 上面的例子中,emitter 为事件 someEvent 注册了两个事件监听器,当someEvent 事件触发后,两个事件监听器回调函数被先后调用

3. EventEmitter 常用属性

3.1 方法
  • on(event, listener):为指定事件注册一个监听器,接受一个字符串event 和一个回调函数。
server.on('connection', function (stream) {
  console.log('someone connected!');
});
  • emit(event, [arg1], [arg2], [...]):按参数的顺序执行每个监听器,如果事件有注册监听则返回true, 否则返回false。

  • addEventListener(event, listener):为指定事件添加一个监听器到监听器数组的尾部。

  • once(event, listener): 为指定事件注册一个单次监听器,即监听器最多只能触发一次,触发后立即解除该监听器。
server.once('connection', function (stream) {
  console.log('Ah, we have our first user!');
});
  • removeListener(event, listener):移除指定事件的某个监听器,监听器必须是该事件已经注册过的。
var callback = function(stream) {
  console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback); // 移除之前注册过的某个事件监听器
  • removeAllListeners([event]):参数可选。没有参数则移除所有事件的所有监听器;如果指定事件参数,则移除指定事件的所有监听器。

  • setMaxListeners(n):EventEmitters 默认添加超过10个监听器就会输出警告信息。可以使用该方法提高监听器的默认限制数量。

  • listeners(event):返回事件的监听器数组。

3.2 类方法
  • listenerCount(emitter, event):返回指定事件的监听器数量。通过EventEmitter类进行调用,而不是通过类对象调用:
var listenerNum = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
3.3 事件
  • newListener(event, listener):该事件在添加新监听器时被触发。
  • removeListener(event, listener):从指定监听器数组中删除一个监听器。该操作会改变处于被删监听器之后的那些监听器的索引。

  • 实例演示:

// main.js文件
var events = require('events');
var eventEmitter = new events.EventEmitter();

var listener1 = function listener1() {   // 定义监听器 1
   console.log('监听器 listener1 执行。');
}

var listener2 = function listener2() {   // 定义监听器 2
  console.log('监听器 listener2 执行。');
}

eventEmitter.addListener('connection', listener1);   // 用 addListener 方法绑定 connection 事件,处理函数为 listener1 

eventEmitter.on('connection', listener2);  // 用 on 方法绑定 connection 事件,处理函数为 listener2

var eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');  // 用 listenerCount 类方法得到connection事件的监听器数量
console.log(eventListeners + " 个监听器监听连接事件。");

eventEmitter.emit('connection');  // 触发 connection 事件 

eventEmitter.removeListener('connection', listener1);  // 移除监绑定的 listener1 函数
console.log("listener1 不再受监听。");

eventEmitter.emit('connection');  // 触发 connection 事件

eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " 个监听器监听连接事件。");

console.log("程序执行完毕。");
  • 上面代码的执行结果为:
$ node main.js
2 个监听器监听连接事件。
监听器 listener1 执行。
监听器 listener2 执行。
listener1 不再受监听。
监听器 listener2 执行。
1 个监听器监听连接事件。
程序执行完毕。

4. error 事件

  • EventEmitter 定义了一个特殊的事件 error,它包含了错误的语义,在遇到异常时会触发 error 事件
  • error被触发时,如果没有绑定 error 的监听器,就会出现异常,导致程序退出并输出错误信息。因此需要为会触发 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃
var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.emit('error'); 

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)

5. 继承 EventEmitter


  • 通常并不会直接使用 EventEmitter ,而是在对象中继承它。包括 fs、net、http,只要是支持事件响应的核心模块都是 EventEmitter 的子类。
  • 使用继承的原因有两点:

    1. 具有某个实体功能的对象实现事件符合语义,事件的监听和发生应该是一个对象的方法;
    1. JS 的对象机制是基于原型的,支持多继承,继承 EventEmitter 不会影响对象原有的继承关系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值