文章目录
  1. Redux源码解析
    1. 1. index.js
    2. 2. createStore
      1. 2.1 store.subscribe
      2. 2.2 store.dispatch
      3. 2.3 store.getState
      4. 2.4 store.replaceReducer
    3. 3. combineReducers
    4. 4. applyMiddleware
    5. 5. 总结

[TOC]

Redux源码解析

关于Redux出现的背景和使用, 这里就不做阐述了, 可以参考redux的源码解析, 我这里直接上简单代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. 定义 action 和 reducer
const action = {
type: "hello",
payload: "hello"
}
const reducer = {
hello: (state, action) => {
return { data: `${action.payload} world`}
}
}
// 2. 创建 store
const store = Redux.createStore(Redux.combineReducers(reducer))
// 3. 监听事件
const unsubscribe = store.subscribe(() => console.log("hello subscriber"))

// 4. dispatch action
store.dispatch(action)
console.log(store.getState().hello); //> hello world

// 5. 取消监听
unsubscribe()

1. index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
* This is a dummy function to check if the function name has been altered by minification.
* If the function has been minified and NODE_ENV !== 'production', warn the user.
*/
// 判断是否压缩, 如果在非production环境使用了压缩文件, 就会报如下warning
function isCrushed() {}

if (
process.env.NODE_ENV !== 'production' &&
typeof isCrushed.name === 'string' &&
isCrushed.name !== 'isCrushed'
) {
warning(
'You are currently using minified code outside of NODE_ENV === "production". ' +
'This means that you are running a slower development build of Redux. ' +
'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' +
'or setting mode to production in webpack (https://webpack.js.org/concepts/mode/) ' +
'to ensure you have the correct code for your production build.'
)
}

// 暴露了的API, 忽略最后一个
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose,
__DO_NOT_USE__ActionTypes
}

2. createStore

先不说combineReducers, 先知道它返回的是个function, 入参是(state, action)即可.
先看 createStore, 内部一堆校验、初始化和函数定义, 主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* reducer: (state, action) => Any
* preloadedState: 默认的state
* enhancer: 增强方法, 比如内置的 applyMiddleware
*
* // 先有个印象, 假设 preloadedState 和 enhancer 我都没有传
*/
export default function createStore(reducer, preloadedState, enhancer) {
// 1. 各种参数校验
// > preloadedState 在 enhancer 存在的时候不能为function, 此时 preloadedState 只能是个 object
// > 因为redux会认为你传了多个enhancer, 抛出异常
if (
(typeof preloadedState === 'function' && typeof enhancer === 'function') ||
(typeof enhancer === 'function' && typeof arguments[3] === 'function')
) {
throw new Error(
'It looks like you are passing several store enhancers to ' +
'createStore(). This is not supported. Instead, compose them ' +
'together to a single function'
)
}

// > 这里对应上面, 如果 preloadedState 是function, 且 enhancer 没有传入
// > 将 preloadedState 赋值给 enhancer
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}

// > 同理, enhancer 必须是个 function
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// > 这里稍微复杂, 后续会说
// > 上面说了, preloadedState和enhancer假设都没传, 代码走不到这里
return enhancer(createStore)(reducer, preloadedState)
}

// > reducer 必须是个 function
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}

// 2. 初始化各种参数
let currentReducer = reducer // 当前reducer对象
let currentState = preloadedState // 当前state对象
let currentListeners = [] // 当前的listeners, 调用subscribe会用到
let nextListeners = currentListeners // currentListeners 的镜像, 类似防止多线程操作的感觉
let isDispatching = false // 是否正在 dispatch

// ------------------------------------------------------
// 一堆函数定义(dispatch, subscribe, getState等), 与上面的变量构成闭包
// ------------------------------------------------------

// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.

// 这里有点意思, 发出一个INIT的action, 一般reducer处理的时候, 都会返回一个默认的 { reducer: state }
// 这里的意思就是把所有reducer执行了一遍, 然后初始化了全局的state tree
dispatch({ type: ActionTypes.INIT })

// 返回store的API
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}

2.1 store.subscribe

现在我们看看subscribe是怎么注册给store的, 想想也知道是放在了currentListeners对象中😏.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* listener: () => Unit, 是个简单的函数
*/
function subscribe(listener) {
// 1. 各种校验
// > listener 必须是个函数
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
// > 如果当前正在dispatch, 抛出异常, 是不允许subscribe操作的
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

/**
* // 函数比较简单, 就是做了下拷贝
* // 记住它, 因为每次操作listeners的时候都会调用
* function ensureCanMutateNextListeners() {
* if (nextListeners === currentListeners) {
* nextListeners = currentListeners.slice()
* }
* }
*/
ensureCanMutateNextListeners()
nextListeners.push(listener)

// 返回一个取消订阅的函数
return function unsubscribe() {
// 校验isSubscribed的值, 第一次调用是true, 调用后变成false
// 防止多次调用
if (!isSubscribed) {
return
}
// 如果当前正在dispatch, 抛出异常, 是不允许subscribe操作的
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.'
)
}

// 置为false, 防止多次调用
isSubscribed = false

// 从listeners中移除该函数
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}

2.2 store.dispatch

开始分析dispatch, 重头戏👻, 不过代码倒是不多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
nction dispatch(action) {
// 1. 各种校验
// > 判断是否是个简单对象, 如果含有很深的原型链, 会返回false. 可以看下isPlainObject的实现
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
// > action必须有type的定义
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
// > 如果正在dispatch, 抛出异常
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}

// 2. 调用reducer
try {
isDispatching = true
// 这个返回的state已经是合并过的了, 是redux的state tree. 先不要在意currentReducer长什么样子
currentState = currentReducer(currentState, action)
} finally { // finally, 调用结束
isDispatching = false
}

// 3. 触发所有的 listener, 没啥毛病
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}

// 4. 返回 action
return action
}

2.3 store.getState

获取Redux的 state tree, 这…., 没啥好说的。注意state中的key就是reducer的key

1
2
3
4
5
6
7
8
9
10
11
function getState() {
if (isDispatching) {
throw new Error(
'You may not call store.getState() while the reducer is executing. ' +
'The reducer has already received the state as an argument. ' +
'Pass it down from the top reducer instead of reading it from the store.'
)
}

return currentState
}

2.4 store.replaceReducer

比较简单, 自行看下

1
2
3
4
5
6
7
8
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}

currentReducer = nextReducer
dispatch({ type: ActionTypes.REPLACE })
}

3. combineReducers

各种校验代码比较多, 大伙耐心看下。⭐️

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* reducers: { key1: reducer1, key2: reducer2, ... }
*/
export default function combineReducers(reducers) {
// 1. 校验reducers的信息
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
// 如果reducer是undefined, 抛出警告
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning(`No reducer provided for key "${key}"`)
}
}
// 如果reducer不是function, 则忽略. 都放到变量finalReducers中
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}

const finalReducerKeys = Object.keys(finalReducers)

// 2. 后面比较state和所有reducer中的key, 将异常的key取出来
let unexpectedKeyCache
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {}
}
// 3. 校验reducer返回的默认state值, 如果是undefined, 抛出异常
let shapeAssertionError
try {
// 这几个无关紧要的方法就不说, 看下就知道了
assertReducerShape(finalReducers)
} catch (e) {
shapeAssertionError = e
}

// 4. 返回方法, 在dispatch的会调用, 这里就串起来了
return function combination(state = {}, action) {
// 1. 各种校验
// > 如果之前存在异常, 抛出
if (shapeAssertionError) {
throw shapeAssertionError
}
// > 处理unexpectedKeyCache, 抛出警告
if (process.env.NODE_ENV !== 'production') {
// 这几个无关紧要的方法就不说, 看下就知道了
const warningMessage = getUnexpectedStateShapeWarningMessage(
state,
finalReducers,
action,
unexpectedKeyCache
)
if (warningMessage) {
warning(warningMessage)
}
}

// 2. 调用reducer方法
let hasChanged = false
const nextState = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
// 获取前一个状态值
const previousStateForKey = state[key]
// 调用reducer, 获取状态值
const nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
// 存放到nextState中
nextState[key] = nextStateForKey
// 判断key的值是否发生变化
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
// 如果变化, 返回nextState, 否则还是返回原state对象
return hasChanged ? nextState : state
}
}

4. applyMiddleware

重点来了, 别看他代码少,真的是太特么难理解了, 高能。⚡️💥✨💉

我先举个栗子, 直接讲容易晕

1
2
3
4
5
6
7
8
9
10
11
12
13
const middleware1 = ({ dispatch }) => next => action => {
console.log("middleware1");
next(action);
}
const middleware2 = ({ dispatch }) => next => action => {
console.log("middleware2");
next(action);
}

const store = Redux.createStore(
Redux.combineReducers(reducers),
Redux.applyMiddleware(middleware1, middleware2)
)

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 在 createStore 中, 如果有enhancer, 那么就如下代码:
* return enhancer(createStore)(reducer, preloadedState)
*/
export default function applyMiddleware(...middlewares) {
// 1. 这里没毛病, 传个createStore函数进来初始化store
return createStore => (...args) => {
// 初始化store
const store = createStore(...args)
// 这里是防止你在定义中间件的时候, 调用dispatch函数
/**
* 比如这样, 就会报错
* ({ dispatch }) => {
* dispatch(xxx)
* return next => action => { }
* }
*/
let dispatch = () => {
throw new Error(
`Dispatching while constructing your middleware is not allowed. ` +
`Other middleware would not be applied to this dispatch.`
)
}
// ⚡️ 核心一: 初始化所有middlewares
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args) // 初始化后, dispatch的指向就变了
}
// 挺好理解, 传入 ({ dispatch }), 返回 next => action => { }
const chain = middlewares.map(middleware => middleware(middlewareAPI))

// ⚡️ 核心二: 组合函数, 看后续
dispatch = compose(...chain)(store.dispatch)

// 2. 返回API, 用新的dispatch代替store中的旧的
return {
...store,
dispatch
}
}
}

分析compose, 有点玄学

1
2
3
4
5
6
7
8
9
10
11
12
// chain: 是 next => action => { } 的集合, 是处理过的middleware的集合
// dispatch = compose(...chain)(store.dispatch)
export default function compose(...funcs) {
// 这里面的arg其实都是 store.dispatch
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

下面分几种情况, 便于理解

  • 1、 如果没有中间件

那么 dispatch = (store.dispatch) => (store.dispatch), 返回默认的dispatch, 没毛病

  • 2、 如果有一个中间件, 假设 chain 是 next => action => { }

那么 dispatch = chain(store.dispatch), 返回是中间件内部的 action => { ... }
然后在使用dispatch action的时候, 会先调用我定义的中间件内部的 action => { ... }, 然后我执行的那个next就是原先的store.dispatch对象, 调用next(action)就是原生dispatch, 这样就串起来了, 没毛病

  • 3、 如果有两个中间件, 返回的是个组合函数, 最不好理解的一个

现在 a和b都是 next => action => { }, args是store.dispatch.
(1)首先执行 b(store.dispatch), 返回的是baction => { }, 传给a这里很关键, a的next其实就是b内部的action => { })
(2)然后执行 a(b内部的action => {}), 返回的是aaction => { }
(3)最后把aaction => { }返回给API使用。

在来看看当我们使用dispatch(action)的时候发生了什么!!!
(1)首先执行a中间件内部的action => { }, 调用next(action), next是b中间件内部的action => { }
(2)b中的next是store.dispatch, 然后在next(action), 这样就串起来了

  • 4、很多中间件, 分析类似, 自行体会.😂

5. 总结

applyMiddleware那块组合函数确实挺精髓的, 还有各种闭包的使用也是特别好, 整个redux源码不是特别多, 给我个人感觉就是:卧槽槽槽!!!写的好屌!!!

文章目录
  1. Redux源码解析
    1. 1. index.js
    2. 2. createStore
      1. 2.1 store.subscribe
      2. 2.2 store.dispatch
      3. 2.3 store.getState
      4. 2.4 store.replaceReducer
    3. 3. combineReducers
    4. 4. applyMiddleware
    5. 5. 总结