Node.js 的 events 模块对外提供了一个 EventEmitter 对象,用于对 Node.js 中的事件进行对立治理。因为 Node.js 采纳了事件驱动机制,而 EventEmitter 就是 Node.js 实现事件驱动的根底。在 EventEmitter 的根底上,Node.js 中简直所有的模块都继承了这个类,以实现异步事件驱动架构。
示例
var events = require('events');
var eventEmitter = new events.EventEmitter();
eventEmitter.on('say',function(name){console.log('Hello',name);
})
eventEmitter.emit('say','Jack');
EventEmitter 模块的 API
addListener 和 removeListener、on 和 off 办法比照
addListener 办法的作用是为指定事件增加一个监听器,其实和 on 办法实现的性能是一样的,on 其实就是 addListener 办法的一个别名。二者实现的作用是一样的,同时 removeListener 办法的作用是为移除某个事件的监听器,同样 off 也是 removeListener 的别名。
var events = require("events")
const {emit} = require("process")
var emitter = new events.EventEmitter()
function hello1(name) {console.log("1", name)
}
function hello2(name) {console.log("2", name)
}
emitter.addListener("say", hello1)
emitter.addListener("say", hello2)
emitter.emit("say", "jake")
// 1 jake
// 2 jake
emitter.removeListener("say",hello1)
emitter.emit("say","jake") // 2 jake
removeListener 和 removeAllListeners
removeListener 办法是指移除一个指定事件的某一个监听器,而 removeAllListeners 指的是移除某一个指定事件的全副监听器。
emitter.removeAllListeners('say');
emitter.emit('say','John');
//removeAllListeners 移除了所有对于 say 事件的监听
// 因而没有任何输入
on 和 once 办法区别
on 和 once 的区别是:on 的办法对于某一指定事件增加的监听器能够继续一直地监听相应的事件;而 once 办法增加的监听器,监听一次后,就会被打消。
emitter.once('see',hello);
emitter.emit('see','Tom');
// 只会输入一次 hello Tom
实现一个 EventEmitter
function EventEmitter() {this.__events = {}
}
EventEmitter.VERSION = '1.0.0';
EventEmitter.prototype.on = function (eventName, listener) {if (!eventName || !listener) return;
// 判断回调的 listener 是否为函数
if (!isValidListener(listener)) {throw new TypeError('listener must be a function');
}
var events = this.__events;
var listeners = events[eventName] = events[eventName] || [];
var listenerIsWrapped = typeof listener === 'object';
// 不反复增加事件,判断是否有一样的
if (indexOf(listeners, listener) === -1) {
listeners.push(listenerIsWrapped ? listener : {
listener: listener,
once: false
});
}
return this;
};
// 判断是否是非法的 listener
function isValidListener(listener) {if (typeof listener === 'function') {return true;} else if (listener && typeof listener === 'object') {return isValidListener(listener.listener);
} else {return false;}
}
// 顾名思义,判断新增自定义事件是否存在
function indexOf(array, item) {
var result = -1
item = typeof item === 'object' ? item.listener : item;
for (var i = 0, len = array.length; i < len; i++) {if (array[i].listener === item) {
result = i;
break;
}
}
return result;
}
on 办法的外围思路就是,当调用订阅一个自定义事件的时候,只有该事件通过校验非法之后,就把该自定义事件 push 到 this.__events 这个对象中存储,等须要登程的时候,则间接从通过获取 __events 中对应事件的 listener 回调函数,而后间接执行该回调办法就能实现想要的成果。
emit,off
EventEmitter.prototype.emit = function(eventName, args) {
// 间接通过外部对象获取对应自定义事件的回调函数
var listeners = this.__events[eventName];
if (!listeners) return;
// 须要思考多个 listener 的状况
for (var i = 0; i < listeners.length; i++) {var listener = listeners[i];
if (listener) {listener.listener.apply(this, args || []);
// 给 listener 中 once 为 true 的进行非凡解决
if (listener.once) {
// 执行一次之后将不再执行
this.off(eventName, listener.listener)
}
}
}
return this;
};
EventEmitter.prototype.off = function(eventName, listener) {var listeners = this.__events[eventName];
if (!listeners) return;
var index;
for (var i = 0, len = listeners.length; i < len; i++) {if (listeners[i] && listeners[i].listener === listener) {
index = i;
break;
}
}
// off 的要害,listeners 数组中去掉绑定事件
if (typeof index !== 'undefined') {listeners.splice(index, 1, null)
}
return this;
};
emit 的解决形式,其实就是拿到对应自定义事件进行 apply 执行,在执行过程中对于一开始 once 办法绑定的自定义事件进行非凡的解决,当 once 为 true 的时候,再触发 off 办法对该自定义事件进行解绑,从而实现自定义事件一次执行的成果。
once,alloff
EventEmitter.prototype.once = function(eventName, listener){
// 间接调用 on 办法,once 参数传入 true,待执行之后进行 once 解决
return this.on(eventName, {
listener: listener,
once: true
})
};
EventEmitter.prototype.allOff = function(eventName) {
// 如果该 eventName 存在,则将其对应的 listeners 的数组间接清空
if (eventName && this.__events[eventName]) {this.__events[eventName] = []} else {this.__events = {}
}
};
once 办法的实质还是调用 on 办法,只不过传入的参数辨别和非一次执行的状况。当再次触发 emit 办法的时候,once 绑定的执行一次之后再进行解绑。
alloff 办法也很好了解了,就是对外部的__events 对象进行清空,清空之后如果再次触发自定义事件,也就无奈触发回调函数了。