【JavaScript】EventEmitter的前端實現


EventEmitter簡介

EventEmitter是Node.js的內置模塊events提供的一個類,它是Node事件流的核心,EventEmitter是服務端的東西,
前端已經有event-emitter的npm庫
 
高級瀏覽器也有原生提供的EventTarget這種實現事件監聽和觸發的API
 
但是它們和Node.js的事件API都有或多或少的區別,今天我們就來實現一個前端版本的EventEmitter
我本章demo的github地址如下
 

API介紹 

我們要實現的API有:
  • on(event, listener):為指定事件注冊一個監聽器,接受一個字符串 event 和一個回調函數。
  • emit(event, [arg1], [arg2]): 按監聽器的順序執行執行每個監聽器
  • addListener(event, listener):on的同名函數(alias)
  • once(event, listener): 和on類似,但只觸發一次,隨后便解除事件監聽
  • removeListener(event, listener): 移除指定事件的某個監聽回調
  • removeAllListeners([event]):移除指定事件的所有監聽回調
  • setMaxListeners(n):用於提高監聽器的默認限制的數量。(默認10監聽回調個產生警告)
  • listeners(event): 返回指定事件的監聽器數組。
為了保證兼容性和簡單性,下面的編碼全部基於ES5語法實現
 

構造函數

首先我們需要寫一個EventEmitter構造函數,給它設置兩個屬性listeners和maxListener
function EventEmitter() {
    this.listeners = {};
    this.maxListener = 10;
}

listeners用於存放事件監聽器函數,結構如下:

{
  "event1": [f1,f2,f3],
  "event2": [f4,f5],
  ...
}

而maxListener 是設置的某個事件能夠添加的監聽器的最大數量,超過這個值,需要在控制台輸出警告,但不會報錯阻止。按照Node的設計,這個值能夠通過setMaxListeners動態調整

on方法

  1. 判斷該事件的監聽器數量是否已超限,超限則報警告
  2. 判斷該事件監聽器數組是否初始化,若未初始化,則將listeners[event]初始化為數組,並加入監聽器cb
  3. 若監聽器數組已經被初始化,則判斷數組中是否已存在cb,不存在則添加,已存在則不做操作。
  4. 指定addListener等於on方法
EventEmitter.prototype.on = function (event, cb) {
    var listeners = this.listeners;
    if (listeners[event] && listeners[event].length >= this.maxListener) {
        throw console.error('監聽器的最大數量是%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方法

  1. 通過Array.prototype.slice.call(arguments)取出方法的參數列表args,(因為考慮簡單性和兼容性所以采用ES5的冗長編碼方式)
  2. 調用args.shift踢掉數組第一個參數即event,留下來的這些是要傳給監聽器的
  3. 遍歷監聽器,通過apply方法把上面得到的args參數傳進去
EventEmitter.prototype.emit = function (event) {
    var args = Array.prototype.slice.call(arguments);
    args.shift();
    this.listeners[event].forEach(cb => {
        cb.apply(null, args);
    });
}

 

removeListener方法

  1. 通過indexOf確定監聽器回調在數組listeners[event]中的位置
  2. 通過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方法的結合:用on方法監聽,在回調結束的最后位置,通過removeListener刪掉監聽函數自身
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]數組
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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM