Redux源碼分析--CreateStore(subscribe)

上一章介紹了Redux源碼分析--CreateStore(getState、subscribe),這一次介紹subscribe及其註銷監聽事件。如果分析的有問題,請及時提醒,謝謝。

整個createStore.js代碼中真正影響到store.subscribe(listener)的有以下幾個:

  • let currentListeners = []; let nextListeners = currentListeners;
  • subscribe方法
  • ensureCanMutateNextListeners方法
  • dispatch方法中監聽事件的循環執行

let currentListeners = []; let nextListeners = currentListeners; 好理解,就是執行createStore()時,簡單的變量初始化,讓currentListeners和nextListeners指針指向同一個空數組。

ensureCanMutateNextListeners

    這個方法作用:當currentListeners和nextListeners指向同一個數組時,就會給nextListeners指向另外一個數組(currentListeners.slice()返回的數組)

下面介紹一下爲啥需要兩個變量來處理listeners監聽事件,如有問題,請提醒,謝謝

    爲什麼需要用兩個變量來定義listeners監聽事件呢?比如:如果只有一個變量存放listeners時,在dispatch方法中,循環執行listeners,要是在某個listener監聽事件中,刪除某個監聽事件,這樣就會可能會影響另外監聽事件的執行。下面用實例來說明下這個問題:

我們先正常情況下,循環運行a/b/c方法,打印出:a b c

let a = () => {console.log('a')};
let b = () => {console.log('b')};
let c = () => {console.log('c')};
let listeners = [a, b, c];
for(let i=0; i<listeners.length; i++) {
	let listener = listeners[i];
	listener();
}

之後,在考慮在執行函數中,註銷掉某個方法,實例如下:

let a = () => {console.log('a')};
let c = () => {console.log('c')};
let listeners = [a];
let b = () => {
	if(listeners.indexOf(c) > -1) {
		const index = listeners.indexOf(c)
      	listeners.splice(index, 1)
	}
	console.log('b')
};

listeners.push(b);
listeners.push(c);

for(let i=0; i<listeners.length; i++) {
	let listener = listeners[i];
	listener();
}

返回結果:a b

剩下的關於subscribe方法,裏面的代碼就比較簡單了。可以說,subscribe是一個閉包函數

subscribe內部代碼實現:

  • 判斷store.subscribe(listener)中listener是不是一個函數,如果否,則拋出一個錯誤“Expected the listener to be a function”
  • 當isDispatching等於true(當reducer在執行的時候)的時候,執行store.subscribe(listener),拋出一個異常
  • isSubscribe變量用於判斷當前監聽事件是否已經註銷
  • 執行ensureCanMutateNextListeners
  • 將listener push到nextListeners裏
  • 返回一個函數(目的是去註銷當前監聽事件)
function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.')
    }

    if (isDispatching) {
      throw new Error(
        'You may not call store.subscribe() while the reducer is executing. ' +
          'If you would like to be notified after the store has been updated, subscribe from a ' +
          'component and invoke store.getState() in the callback to access the latest state. ' +
          'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
      )
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }

      if (isDispatching) {
        throw new Error(
          'You may not unsubscribe from a store listener while the reducer is executing. ' +
            'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
        )
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章