订阅
全部代码,不多。
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了。