node不懂Events模組沒法玩了
阿新 • • 發佈:2018-12-13
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模組原理的介紹,如果有錯誤歡迎指正,本文參考:
- javascript設計模式
作者:夢想攻城獅 連結:https://juejin.im/post/5b990be75188255c7566b479 來源:掘金 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。