Events的重要性:

node是单线程,基于事件驱动的,所以node中很多模块都是基于events去实现的,所以event模块在node中属于很重要的模块。

Events常用的API:

  1. emitter.on(eventName, listener)和emitter.addListener(eventName, listener)用来添加订阅事件
  2. emitter.once(eventName, listener)用来添加只执行一次的事件
  3. emitter.prependListener(eventName, listener)用来在事件队列前面添加事件
  4. emitter.emit(eventName[, ...args])用来触发事件队列执行
  5. emitter.removeListener(eventName, listener)用来移除某个事件队列
  6. EventEmitter.defaultMaxListeners 默认事件队列的长度
  7. emitter.setMaxListeners 设置最大队列的长度
  8. emitter.prototype.getMaxListeners 获取最大队列的长度

Event的核心原理:

events模块是基于发布订阅模式来实现的,其核心的逻辑可以用下面的代码表示:

function Event(){
    this.events=[];
}
//添加订阅者
Events.prototype.on = function(listener){
    if(typeof listener === 'function'){
        this.events.push(listener)
    }
}
//执行订阅回调
Events.prototype.emit = function(){
    this.events.forEach(event=>evetn());
}
复制代码

Events.prototype.on 实现

function EventEmitter(){
    this._events={};//用来存储各种不同类型的事件队列
    this._maxListeners = undefined; // 默认实例上没有最大监听数
}

EventEmitter.defaultMaxListeners//默认事件队列的长度为10

EventEmitter.prototype.setMaxListeners = function(count){
    this._maxListeners = count;
}

EventEmitter.prototype.getMaxListeners = function(){
    if(!this._maxListeners){ // 如果没设置过那就是10个
        return EventEmitter.defaultMaxListeners;
    }
    return this._maxListeners
}
EventEmitter.prototype.on = EventEmitter.prototype.addListener=function(eventName,listener){
    if(!this._events){this._events = Object.create(null);}//防止缓存不存在,创建一个没有原型的干净缓存
    if(eventName!=='newListener'){//newListener每次绑定事件都会调用这个里面的回调并且传入当前事件名
        if(this._events['newListener']){
            this._events['newListener'].forEach(fn=>fn(eventsName))
        }
    }
    if(this.events[eventName]){//已存在队列就直接将回调放入
         if(this._events[eventName].length === this.getMaxListeners()){
            console.warn(`Possible EventEmitter memory leak detected.${this._events[eventName].length}${String(eventName)}listeners added. Use emitter.setMaxListeners() toincrease limit'`)
        }
        this._events[eventName].push(callback);
    }else{//不存在就创建一个队列再放入
        if(this._events[eventName].length === this.getMaxListeners()){
            console.warn(`Possible EventEmitter memory leak detected.${this._events[eventName].length}${String(eventName)}listeners added. Use emitter.setMaxListeners() toincrease limit'`)
        }
        this._events[eventsName]=[listener];
    }
}
module.exports = EventEmitter;
复制代码

Events.prototype.prependListener 实现

EventEmitter.prototype.prependListener = function (eventName,listener) {
  this.on(eventName,listener, true);
}
//修改EventEmitter.prototype.on让其可以选择添加事件的位置
EventEmitter.prototype.on = EventEmitter.prototype.addListener=function(eventName,listener,flag){
    if(!this._events){this._events = Object.create(null);}
    if(eventName!=='newListener'){
        if(this._events['newListener']){
            this._events['newListener'].forEach(fn=>fn(eventsName))
        }
    }
    if(this.events[eventName]){
        if(!flag){//根据flag来判断添加的位置
            this._events[eventName].push(callback);
        }else{
            this._events[eventName].unshift(callback);
        }
    }else{
        this._events[eventsName]=[listener];
    }
}
复制代码

Events.prototype.once 实现

EventEmitter.prototype.once = function(eventName,listener){
    function once(){//once缓存listener,不然的话移除时找不到listener
        listener();
        this.removeListener(eventName,once)
    }
    this.on(eventName,once)
}
复制代码

Events.prototype.emit 实现

EventEmitter.prototype.emit = function(eventName,...args){
    if(this._events[eventName]){
        this._events.forEach(fn=>{//使用箭头函数,所以this指向外层的this即emit实例
            fn.call(this,...args)
        })
    }
}
复制代码

Events.prototype.removeListener 实现

Events.prototype.removeListener = finction(eventName,listener){//需要从相应的事件队列中筛选排除传入的listener
    this._events[eventName].filter(fn=>{
        return listener!==item &&item.g!===listener//第二个针对于用once绑定的事件回调
    })
}
EventEmitter.prototype.once = function(eventName,listener){
    function once(){//once缓存listener,不然的话移除时找不到listener
        listener();
        this.removeListener(eventName,once)
    }
    once.g = listener;//用来缓存原来的listener,删除时用到
    this.on(eventName,once)
}
复制代码

结语:

以上就是关于Events模块原理的介绍,如果有错误欢迎指正,本文参考:

  1. Node API
  2. javascript设计模式


作者:梦想攻城狮
链接:https://juejin.im/post/5b990be75188255c7566b479
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

10-06 10:57