JS 發佈訂閱模式

首先聲明,本文並不是原創。原文請點擊這裏,本文是在原文的基礎上加入一些本身的一些東西,方便之後本身理解與查看。git

發佈訂閱模式

事件發佈/訂閱模式 (PubSub) 在異步編程中幫助咱們完成更鬆的解耦,甚至在 MVC、MVVC 的架構中以及設計模式中也少不了發佈-訂閱模式的參與。github

優勢:在異步編程中實現更深的解耦編程

缺點:若是過多的使用發佈訂閱模式,會增長維護的難度設計模式

實現發佈訂閱模式

var Event = function() {
    this.obj = {}
}

Event.prototype.on = function(eventType,fn) {
    if(!this.obj[eventType]) {
        this.obj[eventType] = []
    }
    this.obj[eventType].push(fn)
}

Event.prototype.emit = function() {
    // 取第一個參數,做爲eventType
    var eventType = Array.prototype.shift.call(arguments);
    //  獲取事件數組
    var arr = this.obj[eventType];
    var len = arr.length;
    // 循環數組,一次執行其中的函數
    for(var i=0;i<len;i++) {
        // 直接調用arr[i],其this指向爲undefined(嚴格模式下)
        // 所以用apply將this指向arr[i]
        // 數組shift函數取出第一個參數,將剩下的參數傳入函數中
        arr[i].apply(arr[i],arguments)
    }
}

var ev = new Event()
ev.on('click',function(a) {  // 訂閱
    console.log(a)
})

ev.emit('click',1)   // 發佈

以上代碼只能實現先訂閱,再發布。直接發佈就會報錯。如何實現能夠先發布,而後訂閱?數組

var Event = function() {
    this.obj = {};
    this.cacheList = [];
}

Event.prototype.emit = function() {
    const args = arguments;  //函數參數
    const that = this;  //this指向,保持cache函數的this指向
    function cache() {
        var eventType = Array.prototype.shift.call(arg)
        var arr = that.obj[eventType]
        for (let i = 0; i < arr.length; i++) {
          arr[i].apply(arr[i], arg)
        }
    }
    this.cacheList.push(cache)  // 採用閉包,保持對emit函數中參數和that的引用
}

Event.prototype.on = function(eventType,fn) {
    if(!this.obj[eventType]) {
        this.obj[eventType] = []
    }
    this.obj[eventType].push(fn)
    // 在訂閱函數中執行emit函數中緩存的函數
    for (let i = 0; i < this.cacheList.length; i++) {
        this.cacheList[i]()
    }
}

改爲這樣後就實現了先發布函數,再訂閱的過程。可是也只能先發布,而後再訂閱,反過來就行不通。緩存

相關文章
相關標籤/搜索