摘要:從異步編程解決方案說起吧事件發布訂閱模式模式流程控制庫事件發布訂閱模式事件監聽器模式是一種廣泛運用于異步編程的模式,是回調函數的事件話,又稱發布訂閱模式。
從node異步編程解決方案說起吧:
事件發布/訂閱模式
Promise/deferred模式
流程控制庫
事件發布/訂閱模式事件監聽器模式是一種廣泛運用于異步編程的模式,是回調函數的事件話,又稱發布/訂閱模式。
主要實現的幾個功能包括
on
remove
once
emit
廢話少說,我們來簡單的實現一個事件監聽函數吧
首先創建一個eventEmitter函數
function EventEmitter() { // 用Object.create(null)代替空對象{} // 好處是無雜質,不繼承原型鏈 // _events來保存觀察著隊列的信息 this._events = Object.create(null); }
因為過多的偵聽器占用大量內存,導致內存泄漏,所以偵聽器的個數一般不會超過10個,否則會有warnning警告??
接下來是一些默認的設置
// 默認最多的綁定次數 EventEmitter.defaultMaxListeners = 10; // 同on方法 EventEmitter.prototype.addListener = EventEmitter.prototype.on; // 返回監聽的事件名 EventEmitter.prototype.eventNames = function () { return Object.keys(this._events); }; // 設置最大監聽數 EventEmitter.prototype.setMaxListeners = function (n) { this._count = n; }; // 返回監聽數 EventEmitter.prototype.getMaxListeners = function () { return this._count ? this._count : this.defaultMaxListeners; };
接下來是on函數的實現
EventEmitter.prototype.on = function (type, cb, flag) { // 不是newListener 就應該讓newListener執行以下 if (type !== "newListener") { this._events["newListener"] && this._events["newListener"].forEach(listener => { listener(type); }); } if (this._events[type]) { // 根據傳入的flag來決定是向前還是向后添加 if (flag) { this._events[type].unshift(cb); } else { this._events[type].push(cb); } } else { this._events[type] = [cb]; } // 監聽的事件不能超過了設置的最大監聽數 if (this._events[type].length === this.getMaxListeners()) { console.warn("警告-監聽器Number過大"); } };
解析:
on函數是幫定的初始函數,首先判斷是否是首次進行偵聽,如果是的話,先進行一遍初始化函數
接下來在——events隊列里找到指針為type的地方,根據flag判斷是在隊列尾還是頭加入callback函數
接下來是once監聽一次的實現方法
// 監聽一次 EventEmitter.prototype.once = function (type, cb, flag) { // 先綁定,調用后刪除 function wrap() { cb(...arguments); this.removeListener(type, wrap); } // 自定義屬性 wrap.listen = cb; this.on(type, wrap, flag); };
解析:
實現為在callback上包裝一層remove操作,再當做一個新的callback傳入on函數
這樣的的話在首次執行回調的時候就會執行remove操作,達到執行一次就刪除的操作
接下來是remove函數,刪除一個type的偵聽器
EventEmitter.prototype.removeListener = function (type, cb) { if (this._events[type]) { this._events[type] = this._events[type].filter(listener => { return cb !== listener && cb !== listener.listen; }); } };
解析:
傳入type和要刪除的callback,對type標記的數組進行 filter操作,假如cb cb === listener則過濾掉
刪除所有
EventEmitter.prototype.removeAllListener = function () { this._events = Object.create(null); };
接下來是發布函數 emit
EventEmitter.prototype.emit = function (type, ...args) { if (this._events[type]) { this._events[type].forEach(listener => { listener.call(this, ...args); }); } };
解析:
也比較直觀,如果events里面存在type的監聽器隊列,則隊列里的每個回調都執行一遍,并且用call函數綁定this和arg
//EventEmitter.js function EventEmitter() { // 用Object.create(null)代替空對象{} // 好處是無雜質,不繼承原型鏈的東東 this._events = Object.create(null); } // 默認最多的綁定次數 EventEmitter.defaultMaxListeners = 10; // 同on方法 EventEmitter.prototype.addListener = EventEmitter.prototype.on; // 返回監聽的事件名 EventEmitter.prototype.eventNames = function () { return Object.keys(this._events); }; // 設置最大監聽數 EventEmitter.prototype.setMaxListeners = function (n) { this._count = n; }; // 返回監聽數 EventEmitter.prototype.getMaxListeners = function () { return this._count ? this._count : this.defaultMaxListeners; }; // 監聽 EventEmitter.prototype.on = function (type, cb, flag) { // 默認值,如果沒有_events的話,就給它創建一個 if (!this._events) { this._events = Object.create(null); } // 不是newListener 就應該讓newListener執行以下 if (type !== "newListener") { this._events["newListener"] && this._events["newListener"].forEach(listener => { listener(type); }); } if (this._events[type]) { // 根據傳入的flag來決定是向前還是向后添加 if (flag) { this._events[type].unshift(cb); } else { this._events[type].push(cb); } } else { this._events[type] = [cb]; } // 監聽的事件不能超過了設置的最大監聽數 if (this._events[type].length === this.getMaxListeners()) { console.warn("警告-警告-警告"); } }; // 向前添加 EventEmitter.prototype.prependListener = function (type, cb) { this.on(type, cb, true); }; EventEmitter.prototype.prependOnceListener = function (type, cb) { this.once(type, cb, true); }; // 監聽一次 EventEmitter.prototype.once = function (type, cb, flag) { // 先綁定,調用后刪除 function wrap() { cb(...arguments); this.removeListener(type, wrap); } // 自定義屬性 wrap.listen = cb; this.on(type, wrap, flag); }; // 刪除監聽類型 EventEmitter.prototype.removeListener = function (type, cb) { if (this._events[type]) { this._events[type] = this._events[type].filter(listener => { return cb !== listener && cb !== listener.listen; }); } }; EventEmitter.prototype.removeAllListener = function () { this._events = Object.create(null); }; // 返回所有的監聽類型 EventEmitter.prototype.listeners = function (type) { return this._events[type]; }; // 發布 EventEmitter.prototype.emit = function (type, ...args) { if (this._events[type]) { this._events[type].forEach(listener => { listener.call(this, ...args); }); } }; module.exports = EventEmitter;
我的博客即將同步至騰訊云+社區,邀請大家一同入駐:https://cloud.tencent.com/dev...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103329.html
摘要:為什么把叫做集合而不能稱為嚴格意義上的對象,來看這個集合的構造函數可以見得,是與處于同一層級的而非是繼承自,所以說由實例出來的對象更加的純凈,并沒有諸如等方法,更像是一個集合。 寫在前面 事件的編程方式具有輕量級、松耦合、只關注事務點等優勢,在瀏覽器端,有著自己的一套DOM事件機制,其中含包括這諸如事件冒泡,事件捕獲等;然而Node的事件機制沒有事件冒泡等,其原理就是設計模式中的觀察者...
摘要:觀察者模式觀察者模式廣泛的應用于語言中,瀏覽器事件如鼠標單擊,鍵盤事件都是該模式的例子。可以看到,這就是觀察者模式的訂閱方法實現。小結通過創建可觀察的對象,當發生一個感興趣的事件時可將該事件通告給所有觀察者,從而形成松散的耦合。 觀察者模式 觀察者模式(observer)廣泛的應用于javascript語言中,瀏覽器事件(如鼠標單擊click,鍵盤事件keyDown)都是該模式的例子。...
摘要:為指定事件注冊一個單次監聽器,即監聽器最多只會觸發一次,觸發后立刻解除該監聽器。移除指定事件的某個監聽器,監聽器必須是該事件已經注冊過的監聽器。返回指定事件的監聽器數組。如何創建空對象我們已經了解到,是要來儲存監聽事件監聽器數組的。 毫無疑問,nodeJS改變了整個前端開發生態。本文通過分析nodeJS當中events模塊源碼,由淺入深,動手實現了屬于自己的ES6事件觀察者系統。千萬不...
摘要:發布訂閱模式訂閱者把自己想訂閱的事件注冊到調度中心,當發布者發布該事件到調度中心,也就是該事件觸發時,由調度中心統一調度訂閱者注冊到調度中心的處理代碼。 發布-訂閱模式,看似陌生,其實不然。工作中經常會用到,例如 Node.js EventEmitter 中的 on 和 emit 方法;Vue 中的 $on 和 $emit 方法。他們都使用了發布-訂閱模式,讓開發變得更加高效方便。 一...
摘要:實例方法的話,最核心的就是分別是添加事件,刪除事件,發布事件。為了防止進程崩潰,可以在對象的事件上注冊監聽器,或使用模塊。注意,模塊已被廢棄。作為最佳實踐,應該始終為事件注冊監聽器。 前言 事件在js中非常的常見,不管是瀏覽器還是node,這種事件發布/訂閱模式的應用都是很常見的。至于發布/訂閱模式和觀察者模式是否是同一種設計模式說法都有,這里不做具體的討論。在之前的項目中也曾自己實現...
閱讀 1266·2021-11-24 09:39
閱讀 1516·2021-09-07 09:59
閱讀 3479·2019-08-30 15:54
閱讀 2474·2019-08-30 11:00
閱讀 2669·2019-08-29 15:06
閱讀 2160·2019-08-26 13:52
閱讀 427·2019-08-26 13:24
閱讀 2489·2019-08-26 12:20