redux源码分析(一)

从源码来解析redux的运作流程,帮助我们更加深刻的理解redux。对于redux的工作流程不了解的同学可以看这篇介绍redux的文章

文件结构

redux的源码并不是很多,大致只分为下列几个文件:
image.png
image.png

index.js是整个代码的入口,主要是判断代码在非生成环境是否压缩暴露出createStore、combineReducers、bindActionCreators、applyMiddleware、compose等方法,如果没有则发出警告⚠️

import createStore from './createStore'
import combineReducers from './combineReducers'
import bindActionCreators from './bindActionCreators'
import applyMiddleware from './applyMiddleware'
import compose from './compose'
import warning from './utils/warning'
import __DO_NOT_USE__ActionTypes from './utils/actionTypes'

/*
 * 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.
 */
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.'
  )
}

export {
  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose,
  __DO_NOT_USE__ActionTypes
}
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

createStore.js

createStore是redux中一个非常重要的API,createStore会生成一个store,维护一个状态树,里面是全局的state.

store = createStore(reducer, preloadedState, enhancer)
1

createStore接受三个参数,分别为reducer纯函数,初始状态,增强器(即 applyMiddleware()返回的内容以及其他的中间件)用法如下:

const enhancer = compose(
    applyMiddleware(sagaMiddleware),
    composeWithDevTools()
);
1
2
3
4

createStore生成的store提供了dispath,subscribe,getState,replaceReducer,observable等方法,接下来逐一分析。

export default function createStore(reducer, preloadedState, enhancer) {
  // 判断接受的参数个数,来指定 reducer 、 preloadedState 和 enhancer
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)
  }

  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }

  let currentReducer = reducer   // 存储当前的reducer
  let currentState = preloadedState  // 存储当前的状态
  let currentListeners = []     // 储存当前的监听函数列表
  let nextListeners = currentListeners  // 储存下一个监听函数列表
  let isDispatching = false  //是否在执行reducer
  }
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

首先判定参数个数,分别指定三个参数,接着判断enhancer是否存在如果存在并且为函数则调用enhancer,并且终止当前函数执行,前面的判断基本上是对三个参数对判断。接下来是对当前状态及reducer的存储。

getState

这里判断是否在执行reducer,返回当前的最新状态state

// 接上述代码,这里不在重复
  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
  }
1
2
3
4
5
6
7
8
9
10
11

dispatch

dispatch接受一个参数action,action 是把数据从应用传到 store 的有效载荷,它是 store 数据的唯一来源,action包含type和payload,payload表示最新的状态state,type代表操作类型。传入action后会首先运行reducer,reducer接收action和当前状态state,reducer通过判断action.type来返回最新的state。

function dispatch(action) {
    // ...一些条件判断
    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    // ....
    return action
  }
1
2
3
4
5
6
7
8
9
10
11

dispatch还会触发整个监听函数列表,所以最后整个监听函数列表都会按顺序执行一遍。dispatch返回值就是传入的action。

function dispatch(action) {
    // ...一些条件判断
   const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }
    return action
  }   

1
2
3
4
5
6
7
8
9
10

subscribe

subscribe会接受一个listener函数,首先运行ensureCanMutateNextListeners函数,ensureCanMutateNextListeners 会根据当前的监听函数列表生成监听函数列表副本。这可以防止用户在中间调用订阅/取消订阅的产生错误

function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
  }
1
2
3
4
5

然后向列表中添加进新的监听函数listenner,subscribe的返回值是一个unsubscribe,是一个解绑函数,调用该解绑函数,会将已经添加的监听函数删除,该监听函数处于一个闭包之中,会一直存在,所以在解绑函数中能删除该监听函数。这就是redux精妙之处。

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

replaceReducer

function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }

    currentReducer = nextReducer
    dispatch({ type: ActionTypes.REPLACE })
  }
1
2
3
4
5
6
7
8

顾名思义replaceReducer的意思就是替换掉reducer,replaceReducer接受一个reducer替换的当前的reducer,之后立即执行dispatch({ type: ActionTypes.INIT }) ,用来初始化store的状态。
replaceReducer的使用场景,分别是:

1.当你的程序要进行代码分割的时候 2.当你要动态的加载不同的reducer的时候 3.当你要实现一个实时reloading机制的时候

observable

该方法并不是暴露给使用者的,一般用于内部,在测试的时候会用到,这里不深究。

最后更新时间: 10/8/2019, 7:41:17 PM