Events的重要性:
node是单线程,基于事件驱动的,所以node中很多模块都是基于events去实现的,所以event模块在node中属于很重要的模块。
Events常用的API:
- emitter.on(eventName, listener)和emitter.addListener(eventName, listener)用来添加订阅事件
- emitter.once(eventName, listener)用来添加只执行一次的事件
- emitter.prependListener(eventName, listener)用来在事件队列前面添加事件
- emitter.emit(eventName[, ...args])用来触发事件队列执行
- emitter.removeListener(eventName, listener)用来移除某个事件队列
- EventEmitter.defaultMaxListeners 默认事件队列的长度
- emitter.setMaxListeners 设置最大队列的长度
- 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模块原理的介绍,如果有错误欢迎指正,本文参考:
- Node API
- javascript设计模式