1. 程式人生 > >node不懂Events模組沒法玩了

node不懂Events模組沒法玩了

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. javascript設計模式

作者:夢想攻城獅 連結:https://juejin.im/post/5b990be75188255c7566b479 來源:掘金 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。