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)
    }
  }

 

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