Nodejs中EventEmitter事件发射器的使用

 2015年05月07日    1490     声明


Nodejs是基于V8引擎实现的事件驱动IO。事件模块Events是Nodejs的核心模块之一,许多模块都继承自Event模块,因此也能够发射事件。例如,http模块创建HTTP服务器时,会发射"connect"事件,断链接时会发射“ close”事件。这些对象在Node中被称为:事件发射击器。需要处理这些事件的对象可以订阅事件,并将回调函数绑定到这些事件上。事件发射器发射事件时,对应的回调函数就会被调用。


理解事件机制

Nodejs事件的使用,会有一个事件发射器及一个或多个事件监听器。事件发射器指可以发射事件的对象,而事件监听器指绑定到事件上的处理代码。

一个简单的web服务器:

var http = require('http');

//创建一个HTTP服务顺
var server = http.createServer();

//监听request事件
server.on('request', function (req, res) { 
    //对request事件的处理	
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World!')
});
server.listen(3000)

在上面的示例中,创建了一个HTTP服务器。每当有web请求进入时,事件发射器(即:server对象)会发送一个'request'类型的事件,而通过'on'注册过的事件监听器里方法会被执行。事件发射器发射的事件是有类型的,如'request'就是一个事件类型,http对象除了有'request'事件外,还有:'connect'、'close'、'upgrade'等类型的事件。


事件发射器的使用

1.实现一个事件发射击器

Nodejs中,自定义一个事件发射非常简单,实现一个继承自event.EventEmitter的伪类。示例如下:

var util = require('util');
var em = require('events').EventEmitter;

var MyClass = function() {
    // body...
}
util.inherits(MyClass, em);

inherits是util模块中方法用于复制父对象中的方法。如,上面的代码中util.inherits就是建立了一条原型链,使MyClass类具有了EventEmitter类的原型方法。


2.发射事件

继承EventEmitter类后,MyClass类的实例就可以发射事件了,添加一个事件发射器:

MyClass.prototype.sendEvent = function(){
    this.emit("myEvent", 'arg 1', 'arg 2');
}

当MyClass类的实例调用sendEvent方法时,就会发送一个myEvent的事件。事件被发射的同时,还可以同时发送一些数据,上面示例中的:'arg 1'和'arg 2'就是被发送的数据。事件被发射时,两个字符串会做为参数发送给事件监听器。

下面实例化MyClass类,并在类实例中创建事件监听,及发送事件:

var myInstance =  new MyClass();

//事件监听器
myInstance.on('myEvent', function(arg1, arg2){
    console.log('这是监听到的事件,这个事件还发来了两个参数%s和%s', arg1, arg2);
})
//事件发送器发射事件
myInstance.sendEvent();

//输出如下:
这是监听到的事件,这个事件还发来了两个参数arg 1和arg 2


事件发射器相关API

任何实现了EventEmitter类的对象,都具有了EventEmitter类中的方法。EventEmitter中的方法包括:

.addListener和.on:为指定类型的事件添加事件监听器
.once:为指定类型的事件添加一个仅使用一次的事件监听器
.removeListener:删除绑定到指定事件上的某个事件监听器
.removeAllListeners:删除绑定到指定事件上的所有事件监听器
.setMaxListeners:设置可添加的监听器的数量


1.使用.addListener()或.on()绑定回调函数

通过事件类型和回调函数,就可以注册事件发生时所要进行的操作,即添加事件监听。如上面示例中的myInstance.on()方法,就是添加了事件监听器。.on()方法是.addListener()的简写形式,二者在功能上完全一致。

事件发射器允许在同一类型的事件上绑定多个事件监听器,例如:

var myInstance =  new MyClass();
//事件监听器
myInstance.on('myEvent', function(arg1, arg2){
    console.log('这是监听到的事件,这个事件还发来了两个参数%s和%s', arg1, arg2);
})
//另一个事件监听器
myInstance.on('myEvent', function(arg1){
    console.log('这是另一个事件监听到器,这个事件只接受一个参数%s', arg1);
})
//事件发送器发送事件
myInstance.sendEvent();

//以上代码输出如下:
这是监听到的事件,这个事件还发来了两个参数arg 1和arg 2
这是另一个事件监听到器,这个事件只接受一个参数arg 1

当添加多个事件监听器时,事件发射器会按照事件监听器的注册顺序依次调用监听事件。当其中一个事件发生错误时,其后注册的监听事件将不会再被调用。为防止因为监听器太多而可能导致内存泄漏,Nodejs默认允许对一类型事件添加10个监听器,超过10个将会得到一条警告。可以通以下方法设置可添加监听器的数量:

emitter.setMaxListeners(20);    //设置为0时,则不限制监听器数量


2.使用.once()绑定仅执行一次的回调函数

如果想使监听器里面的函数只执行一次,可以使用.once()函数,.once()注册事件监听器后,会在第一个事件发生成删除事件监听。示例如下:

var myInstance =  new MyClass();

//只执行一次的事件监听器
myInstance.once('myEvent', function(arg1, arg2){
    console.log('这是一个只执行一次的事件监听器。这个监听器收到了两个参数%s和%s', arg1, arg2);
})
//多次发送事件
myInstance.sendEvent();
myInstance.sendEvent();

//以上代码输出如下:
这是一个只执行一次的事件监听器。这个监听器收到了两个参数arg 1和arg 2


3.事件监听器的移除

如果需要删除绑定到指定事件上的某个事件监听器,可以调用removeListener()方法,通过事件类型和回调函数名来取消事件临听器的注册。示例如下:

var myInstance =  new MyClass();

//监听函数1
function myListener1(arg1, arg2){
    console.log('事件监听器1');
}
//监听函数2
function myListener2(arg1, arg2){
    console.log('事件监听器2');
}
//添加事件监听器
myInstance.on('myEvent', myListener1);
myInstance.on('myEvent', myListener2);
//发送事件
myInstance.sendEvent();
//移除事件临器1
myInstance.removeListener('myEvent', myListener1);
//再次发送事件
myInstance.sendEvent();

//以上代码输出如下:
事件监听器1
事件监听器2
事件监听器2

以上代码是移除了某事件类型的单个监听器,也可以调用.removeAllListeners()方法,移除某类型事件的所有的监听器。示例如下:

var myInstance =  new MyClass();

//监听函数1
function myListener1(arg1, arg2){
    console.log('事件监听器1');
}
//监听函数2
function myListener2(arg1, arg2){
    console.log('事件监听器2');
}
//添加事件监听器
myInstance.on('myEvent', myListener1);
myInstance.on('myEvent', myListener2);
//发送事件
myInstance.sendEvent();
//按事件类型和监听函数名称移除监听器的注册
myInstance.removeAllListeners('myEvent');
//再次发送事件
myInstance.sendEvent();

//以上代码输出如下:
事件监听器1
事件监听器2