EventEmitter簡(jiǎn)介
EventEmitter是Node.js的內(nèi)置模塊events提供的一個(gè)類,它是Node事件流的核心,EventEmitter是服務(wù)端的東西,
前端已經(jīng)有event-emitter的npm庫 地址:?https://www.npmjs.com/package/event-emitter
<https://www.npmjs.com/package/event-emitter> ?
高級(jí)瀏覽器也有原生提供的EventTarget這種實(shí)現(xiàn)事件監(jiān)聽和觸發(fā)的API 地址:?
https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget
<https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget> ?
但是它們和Node.js的事件API都有或多或少的區(qū)別,今天我們就來實(shí)現(xiàn)一個(gè)前端版本的EventEmitter 我本章demo的github地址如下
https://github.com/penghuwan/event-emitter
<https://github.com/penghuwan/event-emitter> ?
API介紹?
我們要實(shí)現(xiàn)的API有:
* on(event, listener):為指定事件注冊(cè)一個(gè)監(jiān)聽器,接受一個(gè)字符串 event 和一個(gè)回調(diào)函數(shù)。
* emit(event, [arg1], [arg2]): 按監(jiān)聽器的順序執(zhí)行執(zhí)行每個(gè)監(jiān)聽器
* addListener(event, listener):on的同名函數(shù)(alias)
* once(event, listener): 和on類似,但只觸發(fā)一次,隨后便解除事件監(jiān)聽
* removeListener(event, listener): 移除指定事件的某個(gè)監(jiān)聽回調(diào)
* removeAllListeners([event]):移除指定事件的所有監(jiān)聽回調(diào)
* setMaxListeners(n):用于提高監(jiān)聽器的默認(rèn)限制的數(shù)量。(默認(rèn)10監(jiān)聽回調(diào)個(gè)產(chǎn)生警告)
* listeners(event): 返回指定事件的監(jiān)聽器數(shù)組。 為了保證兼容性和簡(jiǎn)單性,下面的編碼全部基于ES5語法實(shí)現(xiàn) ?
構(gòu)造函數(shù)
首先我們需要寫一個(gè)EventEmitter構(gòu)造函數(shù),給它設(shè)置兩個(gè)屬性listeners和maxListener function
EventEmitter() {this.listeners = {}; this.maxListener = 10; }
listeners用于存放事件監(jiān)聽器函數(shù),結(jié)構(gòu)如下:
{ "event1": [f1,f2,f3], "event2": [f4,f5], ... }
而maxListener 是設(shè)置的某個(gè)事件能夠添加的監(jiān)聽器的最大數(shù)量
,超過這個(gè)值,需要在控制臺(tái)輸出警告,但不會(huì)報(bào)錯(cuò)阻止。按照Node的設(shè)計(jì),這個(gè)值能夠通過setMaxListeners動(dòng)態(tài)調(diào)整
on方法
* 判斷該事件的監(jiān)聽器數(shù)量是否已超限,超限則報(bào)警告
* 判斷該事件監(jiān)聽器數(shù)組是否初始化,若未初始化,則將listeners[event]初始化為數(shù)組,并加入監(jiān)聽器cb
* 若監(jiān)聽器數(shù)組已經(jīng)被初始化,則判斷數(shù)組中是否已存在cb,不存在則添加,已存在則不做操作。
* 指定addListener等于on方法 EventEmitter.prototype.on = function (event, cb) { var
listeners =this.listeners; if (listeners[event] && listeners[event].length >=
this.maxListener) { throw console.error('監(jiān)聽器的最大數(shù)量是%d,您已超出限制', this.maxListener)
}if (listeners[event] instanceof Array) { if (listeners[event].indexOf(cb) ===
-1) { listeners[event].push(cb); } } else { listeners[event] = [].concat(cb); }
} EventEmitter.prototype.addListener= EventEmitter.prototype.on;
emit方法
*
通過Array.prototype.slice.call(arguments)取出方法的參數(shù)列表args,(因?yàn)榭紤]簡(jiǎn)單性和兼容性所以采用ES5的冗長(zhǎng)編碼方式)
* 調(diào)用args.shift踢掉數(shù)組第一個(gè)參數(shù)即event,留下來的這些是要傳給監(jiān)聽器的
* 遍歷監(jiān)聽器,通過apply方法把上面得到的args參數(shù)傳進(jìn)去 EventEmitter.prototype.emit = function
(event) {var args = Array.prototype.slice.call(arguments); args.shift(); this
.listeners[event].forEach(cb => { cb.apply(null, args); }); }
?
removeListener方法
* 通過indexOf確定監(jiān)聽器回調(diào)在數(shù)組listeners[event]中的位置
* 通過splice(i,1)刪除之 EventEmitter.prototype.removeListener = function (event,
listener) {var listeners = this.listeners; var arr = listeners[event] || []; var
i = arr.indexOf(listener); if (i >= 0) { listeners[event].splice(i, 1); } }
once方法
once方法是on方法和removeListener方法的結(jié)合:用on方法監(jiān)聽,在回調(diào)結(jié)束的最后位置,通過removeListener刪掉監(jiān)聽函數(shù)自身
EventEmitter.prototype.once =function (event, listener) { var self = this;
function fn() { var args = Array.prototype.slice.call(arguments);
listener.apply(null, args); self.removeListener(event, fn); } this.on(event,
fn) }
removeAllListener方法
清空listeners[event]數(shù)組 EventEmitter.prototype.removeAllListener = function
(event) {this.listeners[event] = []; }
setMaxListeners方法和listeners方法
EventEmitter.prototype.listeners = function (event) { return this
.listeners[event]; } EventEmitter.prototype.setMaxListeners= function (num) {
this.maxListener = num; }
?
Github地址
https://github.com/penghuwan/event-emitter
<https://github.com/penghuwan/event-emitter>
熱門工具 換一換