EventEmitter

当继承EventEmitter,成为其子类就具备了emit激发事件方法和addListener添加监听器的方法。在node.js核心库中很多类都继承自EventEmitter,例如前面章节介绍的stream和socket等操作,有类似于 on("...",function(){}) 的写法。

下面做一个实例:

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

// 定义一个EventEmitter子类
function User(name){
   EventEmitter.call(this);
   this._name = name;
}

inherits(User,EventEmitter);

User.prototype.changeName = function(name){
    this._name = name;
    // 激发change name事件
    this.emit("change name",name);
}

// 创建一个User对象
var me = new User("leo");
me.on("change name",function(newName){
    console.log("名字被改成成 ---> " + newName);
});

me.changeName("brighthas");

User类继承了EventEmitter,changeName被调用后,通过emit激发change name事件。后面创建一个User对象me,通过me.on方法添加一个change name事件的监听器,后面调用me.changeName方法后,激发了change name事件,从而调用了监听器,打印出:

名字被改成成 ---> brighthas

下面详细分析一下EventEmitter对象所具备的方法。

添加监听器

emitter.addListener(event, listener) 和 emitter.on(event, listener) 方法写法不同而已,都是向emitter对象添加监听器,event是事件名称,listener是监听器函数。

googogemitter.once(event, listener) 和 emitter.on 用法一致,区别是添加的监听器只监听一次,如果第二次发生同样事件,事件监听器将不会被执行。

emitter.on("event name",function(arg0,arg1 ...){
   ...
})

监听器参数取决于emit激发事件时的赋值,emitter.emit("event name",111,222,234),那么监听器的实参arguments的值是 [111,222,333]。

激发事件

通过emitter.emit方法激发事件。emitter.emit(event, [arg1], [arg2], [...])

删除事件监听器

通过emitter.removeListener(event, listener)方法,可以删除event事件的listener监听器,看如下代码。

var EventEmitter = 
    require("events").EventEmitter,
    inherits = require("util").inherits;
    // 定义一个EventEmitter子类 
    function User(name){   
    EventEmitter.call(this);   
    this._name = name; 
    }
inherits(User,EventEmitter);
User.prototype.changeName = function(name){    
this._name = name;    // 激发change name事件    
this.emit("change name",name); 
}
// 创建一个User对象 var me = new User("leo");
// 第一个监听器 
function handle1(name){    
console.log("handle1 --- > 新名字:"+name); 
}
// 第二个监听器 
function handle2(name){    
console.log("handle2 --- > 新名字:"+name); 
}
me.on("change name",handle1); me.on("change name",handle2);
me.changeName("brighthas");



这个代码结果是:

handle1 --- > 新名字:brighthas
handle2 --- > 新名字:brighthas

如果把代码改一下,在 me.on("change name",handle2); 之后加上一行代码,在执行看看效果。

...
me.on("change name",handle1);
me.on("change name",handle2);

// 新添加的代码
me.removeListener("change name",handle1);

me.changeName("brighthas");

执行结果:

handle2 --- > 新名字:brighthas

通过me.removeListener("change name",handle1) 这行代码删除了change name 事件的handle1监听器,这样当激发change name 事件时,只有handle2监听器被执行。

emitter.removeAllListeners([event]) 如果这个方法的 event 参数没有指定那个事件,那么将会删除emitter对象内的全部事件监听器。如果指定了事件名称,那么会删除这个事件全部的监听器。

emitter.listeners(event)

这个方法是返回指定事件的全部监听器。

emitter.setMaxListeners(n)

这个是设置针对一个事件最多能添加多少监听器,默认是10。 如果超过这个值会有警告提示,程序还是会照常运行。

以上是对象方法,下面介绍一下类方法。

EventEmitter.listenerCount(emitter, event)

这个类方法可以得到emitter的event事件的监听器数量。

emitter本身发出的事件

newListener事件,当通过 emitter.on / emitter.once 添加监听器时会触发该事件。

removeListener 事件,当通过 emitter.removeAllListeners / emitter.removeListener 删除监听器时会触发该事件。

看下面代码:

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

// 定义一个EventEmitter子类
function User(name){
   EventEmitter.call(this);
   this._name = name;
}

inherits(User,EventEmitter);

User.prototype.changeName = function(name){
    this._name = name;
    // 激发change name事件
    this.emit("change name",name);
}

// 创建一个User对象
var me = new User("leo");

// 第一个监听器
function handle1(name){
    console.log("handle1 --- > 新名字:"+name);
}

// 第二个监听器
function handle2(name){
    console.log("handle2 --- > 新名字:"+name);
}

// 添加 newListener事件监听
me.on("newListener",function(event,listener){
    console.log(event + "事件添加了一个监听器")
})

// 添加 removeListener事件监听器
me.on("removeListener",function(event,listener){
    console.log(event+"事件删除了一个监听器");
})

me.on("change name",handle1);
me.on("change name",handle2);
// 删除全部事件监听器
me.removeAllListeners();
me.changeName("brighthas");

打印结果:

removeListener事件添加了一个监听器
change name事件添加了一个监听器
change name事件添加了一个监听器
newListener事件删除了一个监听器
change name事件删除了一个监听器
change name事件删除了一个监听器
【小结】

这里要说明的是,很多人会把并发 I/O非阻塞 等概念和事件概念有混淆,至少是部分混淆,其实毫无关系。事件也不能决定是异步还是同步,这个取决于底层。