Redux源码分析——1,订阅,取消订阅

订阅

全部代码,不多。

function subscribe(listener: () => void) {
    
    
  //参数不是函数,报错。
  if (typeof listener !== 'function') {
    
    
    throw new Error(
      `Expected the listener to be a function. Instead, received: '${
      
      kindOf(
        listener
      )}'`
    )
  }
  //是否正在执行中
  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/store#subscribelistener for more details.'
    )
  }
  //打开标记,是订阅
  let isSubscribed = true
  //确保next和current不是同一个对象
  ensureCanMutateNextListeners()
  //next添加
  nextListeners.push(listener)
  //返回函数,取消订阅
  return function unsubscribe() {
    
    
  //...
  }
}

1,判断参数。如果不是函数,报错。

if (typeof listener !== 'function') {
    
    
  throw new Error(
    `Expected the listener to be a function. Instead, received: '${
      
      kindOf(
      listener
    )}'`
  )
}

2,如果正在执行中,报错。

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/store#subscribelistener for more details.'
  )
}

3,打开标记,是订阅。

let isSubscribed = true

4,确保next和current不是同一个对象。

如果是,current复制给next。

ensureCanMutateNextListeners()

function ensureCanMutateNextListeners() {
    
    
  if (nextListeners === currentListeners) {
    
    
    nextListeners = currentListeners.slice()
  }
}

5,next数组添加

nextListeners.push(listener)

6,返回取消订阅的函数。

return function unsubscribe() {
    
    
	//...
}

取消订阅

也很简洁嗷。

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/store#subscribelistener for more details.'
    )
  }
  //变成无订阅状态
  isSubscribed = false
  //确保next和current不是一个对象
  ensureCanMutateNextListeners()
  //获取当前订阅者的索引
  const index = nextListeners.indexOf(listener)
  //切掉它
  nextListeners.splice(index, 1)
  //清除缓存
  currentListeners = null
}

1,不是订阅直接返回。

这个标记是订阅时开启的。

if (!isSubscribed) {
    
    
  return
}

2,如果正在执行中,报错。

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

3,关闭标记。

isSubscribed = false

4,再次确保不是同一个对象。

ensureCanMutateNextListeners()

5,next数组移除元素。

//获取当前订阅者的索引
const index = nextListeners.indexOf(listener)
//切掉它
nextListeners.splice(index, 1)

6,current赋值null

currentListeners = null

关键操作分析

1,订阅,取消订阅

订阅:数组添加。
取消订阅:数组移除。

这就有点像这一篇文章:https://blog.csdn.net/qq_37284843/article/details/123361179
(手写跨组件通信)

2,订阅标记

订阅时打开标记。

取消订阅时判断一下:
关闭:直接返回。
没关闭:切换为关闭,后续关闭操作。

这就很智能,让取消订阅只会触发一次。

3,执行中标记

isDispatching

订阅时判断一下,true就报错。
取消时判断一下,true就报错。

4,双缓冲

反复地确保next和current不是同一个对象:

ensureCanMutateNextListeners()

function ensureCanMutateNextListeners() {
    
    
  if (nextListeners === currentListeners) {
    
    
    nextListeners = currentListeners.slice()
  }
}

每次都是current复制一份给next。

next:负责修改。
添加和移除,都是操作它。

current:负责查询。
这里没有用到,最后的时候赋值null了。

猜你喜欢

转载自blog.csdn.net/qq_37284843/article/details/123642825