簡單剖析Node中的事件監聽機制(一)

使用js的class類簡單的實現一個事件監聽機制,不一樣於瀏覽器中的時間綁定與監聽,相似於node中的時間監聽,而且會在接下來的文章中去根據本身的理解去寫一下Event模塊中的原理。node

Node.js使用了一個事件驅動、非阻塞式I/O的模型,使其輕量又高效。而且Node中的大量模塊都使用了Event機制,所以能夠說是整個Node中最重要的模塊之一。git

實例:github

let event = new eventEmitter();
    event.on('someType',function(){
        
    });
    event.emit('someType');

依據上述例子,手動觸發一個類型的事件,調用監聽的回調函數,能夠先來實現一個最爲簡單的小例子,例以下放代碼:瀏覽器

class eventEmitter {
    constructor() {
        this.callEvent = '';
    }
    on(eventType, callback) {
        this.callEvent = callback;
    };
    emit(eventType) {
        this.callEvent();
    };
}
let event = new eventEmitter();
event.on('click', function () {
    console.log('click')
});
event.emit('click');

上述實現的代碼,可以簡單的實現,當咱們執行emit()方法時,去執行本來on()中傳入的回調函數。
咱們知道node中的Event模塊是一個簡單的事件監聽模式的實現。Event模塊中只提供了一個對象EventEmitter,EventEmitter的核心就是事件監聽與事件觸發的監聽功能的封裝。函數

EventEmitter可讓咱們註冊一個或者多個函數做爲listeners,在特定的事件觸發時被調用。咱們去監聽的函數就是listeners。固然,咱們能夠註冊多個監聽事件,因此須要一個map結構來存儲監聽事件和回調函數的對應關係。優化

在EventEmitter類中,已鍵值對的方式來存儲事件名和對應的監聽器。this

首先根據上邊的類來實現咱們on事件,先來個events來做爲存儲的鍵值對,每次傳入的值爲事件類型和回調函數,代碼簡單以下:prototype

EventEmitter.prototype.on = function on(type,listener){
    return _on(this,type,listener);
};

function _on(target,type,listener){
    var m;
    var events;
    var existing;
    if(typeof listener !== 'function'){
        throw new Error("監聽者必須是一個函數");
    }
    //獲取到對象上的監聽事件鍵值對
    events = target._events;
    if(!events){
        //若是沒有鍵值對,則從新自定義
        events = target._events = {};
        target._eventsCount = 0;
    }else{
        //獲取原來鍵值對中的listener事件
        existing = events[type];
    }

    if(!existing) {
        //若是本來的事件監聽的鍵值對中沒有該type的該監聽事件
        //則在events中存放該type和該監聽事件的鍵值對
        existing = events[type] = listener;
        //而且當前內存中存放的監聽事件加1
        ++target._eventsCount;
    }

    return target;
}

如今on事件可使用了,咱們先不去思考最大監聽數的限制還有鍵值對的初始化不正確等其餘因素,這些能夠放在以後進行優化,接下來簡單的去實現EventEmitter中的emit事件code

EventEmitter.prototype.emit = function emit(type){
    return _emit(this,type);
};

function _emit(target,type){
    var events,exiting,handler;
    if(!type){
        throw new Error('觸發的事件不能爲空');
    }
    //獲取到對象上的監聽事件鍵值對
    events = target._events;
    //根據type獲取到監聽事件
    handler = events[type];
    if(!handler){
        return false;
    }
    handler();
}

一樣的emit事件的實現是簡單的從鍵值對中根據type獲取到監聽事件去執行。這裏尚未考慮傳入多個參數的狀況。對象

根據上邊的簡單實現,咱們能夠來進行下嘗試,比以前的版本相比,咱們能夠監聽多個事件,去觸發多個回調函數了。

event.on('click', function () {
    console.log('click')
});

event.on('click1',function (){
    console.log('click11');
});

event.emit('click');
//輸出click

event.emit('click1');
//輸出click11

console.log(event._events);
//輸入{click: [Function],click1:[Function]}

這裏簡單的實現了多個事件註冊,多個事件觸發的EventEmitter,接下來會繼續進行設置監聽個數、以及觸發時傳入多個參數的剖析。

參考:[https://github.com/nodejs/node/blob/v6.0.0/lib/events.js]

相關文章
相關標籤/搜索