1.EventEmittet简单介绍
events模块是nodejs服务端知识,但是大多数Node.js核心都是基于异步的思想进行开发的events模块也不例外。
- Node.js的events模块对外提供了EventEmitter对象,用于对Node.js中的事件进行统一管理
- 在EventEmitter的基础上,几乎所有的模块都继承了这个类,以实现异步事件驱动框架。
2.EventEmitter基本用法
var events = require('events');
var eventBus = new events.EventEmitter();
eventBus.on('say',function(message, name){
console.log(message, name);
})
eventBus.emit('say','Hello','Join')
EventEmitter常用的API:
3. 手写实现浏览器端的EventEmitter
EventEmitter采用的是发布-订阅模式,发布-订阅模式其实是观察者模式的一种变形,区别在于:发布-订阅模式在观察者模式基础上增加了一个调度中心。
// 初始化代码
function EventEmitter(){
this.__events={}
}
EventEmitter.VERSION='1.0.0'
// 实现on方法
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 listenerWrapped = typeof listener === "object";
// 不重复添加事件,判断是否有一样的
if(indexOf(listeners, listener)===-1){
listeners.push(listenerWrapped?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
}
// 实现触发
EventEmitter.prototype.emit = function(eventName, args){
// 直接通过内部对象获取对应自定义事件的回调函数
var listener = this.__events[eventName];
if(!listener) return;
// 需要考虑多个listener的情况
for(var i=0; i<listener.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关键字
if(typeof index!=='undefined'){
listeners.splice(index, i, null)
}
return this
}
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={}
}
}