阅读 4335

redux源码解析

前言

相信很多同学跟我一样对目前比较流行的前端库的原理和实现 很感兴趣,比如(react, vue, webpack, redux, react-redux, react-router...等等等), 但是一开始阅读源码的时候难免有些不顺手, 本文以redux的源码解读为例,为你提供一些解读源码的思路,本文为我解读redux源码的全过程,其中也会有一些弯路, 不过还是分享给大家,毕竟本文倡导重在阅读过程。

话不多说,我们直接开始手撸redux

github上找到redux,clone到本地

  目前最新版本: 4.0.1
复制代码

打开项目, 我的习惯是先瞄一眼package,看一下相关依赖,有没有peerDependencies等

现在开上去没什么值得看的, 了解一下用rollup打包即可,然后看一下文件夹, 结构比较常规,我们直接看src,并没有太多的文件, 怎么样?是不是有了信心?

个人觉得再看别人的代码时debugger是一个很好的东西, 可以查看执行顺序提高效率。

好的,那我们就把redux拿出来,可以debugger就方便多了。

想直接撸码的同学直接跳过这一步,看后面

先用一个你比较熟悉的脚手架快速搭建一个react工程(因为后续会解析react-redux,所以直接用react工程),比如我选择create-react-app

  create-react-app redux-source-analyse
复制代码

把redux中的src改名为redux放在redux-source-analyse项目的src下, 接下来由于作者考虑到阅读react-redux的时候也需要有一个这样的项目,直接把redux官网的todoList项目考到了该项目中,打开项目目录是这样的(其实redux源码不需要使用这个todolist)

不想这么麻烦的同学可以直接clone这个项目里面注释很详细, 建议结合此项目来看本文。

我们正式开始撸源码

根据常识,最开始我们当然选择看index.js文件

嘿嘿,很简单吧, 看下引用,没有外部的包,然后返回了一个对象, 这个对象当然就是我们引用的redux啦,

isCrushed.name !=='isCrushed'用来判断是否压缩过,如果不是production环境且压缩了,给出warning
复制代码

接下来我们看比较核心的createStore.js

先来看看他是怎么用的, 是function, 参数 initState, applyMiddleware可选

 const store = createStore(rootReducer, initState, applyMiddleware(logger));
复制代码

接着,过一下大体都是什么东西

直接看代码,对应的解释以注释,作者是先从上向下看的,先看参数规范的部分(... throw new Error('....') ...) 接着看一下function,这里推荐先看redux暴露出来的api,比如getState,subscribe, dispatch, 遇到相关的function直接进去看一下, 哪怕是utils里面的辅助函数(当然因为redux的辅助函数比较简单,如果阅读其他库,复杂的地方可以先跳过,不过要搞清楚函数的功能),阅读不太顺利,需要自己debugger的同学下载他

基本阅读步骤 (... throw new Error('....') ...)-> let xxx -> getState -> subscribe -> dispatch -> replaceReducer -> observable

import ?observable from 'symbol-observable'

import ActionTypes from './utils/actionTypes'
import isPlainObject from './utils/isPlainObject'

// 先看这里, 就是我们调用的createStore function了
export default function createStore(reducer, preloadedState, enhancer) {
  // 如果 preloadedState和enhancer都为function,不支持,throw new Error
  // 我们都知道[initState]为object, [enhancer]为function

  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为undefined的时候说明initState没有初始化, 但是有middleware
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState // 把 preloadedState 赋值给 enhancer
    preloadedState = undefined // preloadedState赋值undeifined
  }

  // debugger
  // 如果参数enhancer存在
  if (typeof enhancer !== 'undefined') {
    // 如果enhancer存在,那他必须是个function, 否则throw Error哈
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    /**
     * 传入符合参数类型的参数,就可以执行 enhancer, 
     * 但是这个return深深的吸引了我, 因为说明有applyMiddleware的时候后面的都不用看了 ??? 当然不可能
     * 可是applyMiddleware其实是必用项,所以猜想一下applyMiddleware强化store之后会enhancer赋值undefined,再次调用createStore
     * 上下打个debugger看一下执行顺序(debugger位置以注释),果然不出所料
     * 好了, 假设我们还不知道applyMiddleware()这个funcrion具体干了什么,
     * 只知道他做了一些处理然后重新调用了createStore并且enhancer参数为undefined
     * 先记下,后续在看applyMiddleware, 因为我们现在要看的是createStore
     * * */
    // debugger
    return enhancer(createStore)(reducer, preloadedState)
  }
  // debugger

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

  // 简单过一下定义的变量
  let currentReducer = reducer  // 临时reducer
  let currentState = preloadedState // 临时init state
  let currentListeners = []  // 看名字,是个数组,起名Listeners,想到了什么? 我想到的是监听队列和观察者模式
  let nextListeners = currentListeners // 浅拷贝下这个队列
  let isDispatching = false // 我们很容易先假设isDispatching标志是否正在执行dispatch

  // 先看下各个函数的名字, 打眼一看getState,dispatch,subscribe都是比较熟悉的api
  // subscribe,observable再加上定义的数组,应该肯定是监听队列和观察者模式
  // 那我们先看看比较熟悉且暴露出来的api好了先看 -> getState

  // 其实这里是保存一份订阅快照
  function ensureCanMutateNextListeners() {
    //  不要忘了let nextListeners = currentListeners // 浅拷贝下这个队列
    // 判断nextListeners和当前的currentListeners是不是一个引用
    if (nextListeners === currentListeners) {
      // 如果是一个引用的话深拷贝出来一个currentListeners赋值给nextListener
      nextListeners = currentListeners.slice()
    }
  }

  // store.getState()获取当前的state
  function getState() {
    // dispatch中不可以getState, 为什么?
    // 因为dispatch是用来改变state的,为了确保state的正确性(获取最新的state),所有要判断啦
    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.'
      )
    }
    // 确定currentState是当前的state 看 -> subscribe
    return currentState
  }

  // store.subscribe方法设置监听函数,一旦触发dispatch,就自动执行这个函数
  // listener是一个callback function
  function subscribe(listener) {
    // 类型判断
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.')
    }

    // 同理不可以dispatch中
    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干啥的,点击去看一下
    ensureCanMutateNextListeners()
    // push一个function,明显的观察者模式,添加一个订阅函数
    nextListeners.push(listener)
    // 返回取消的function(unsubscribe)
    return function unsubscribe() {
      // 还记得let isSubscribed = true吧, 用来标记是否有listerner的
      if (!isSubscribed) {
        // 没有直接return
        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,
      isSubscribed = false

      // 保存订阅快照
      ensureCanMutateNextListeners()
      // 找到并删除当前的listener
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

  // 发送一个action
  function dispatch(action) {
    // 看下util的isPlainObject
    // acticon必须是由Object构造的函数, 否则throw Error
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
          'Use custom middleware for async actions.'
      )
    }

    // 判断action, 不存在type throw Error
    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
          'Have you misspelled a constant?'
      )
    }

    // dispatch中不可以有进行的dispatch
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      // 执行时标记为true
      isDispatching = true
      // 执行reducer, 来,回忆一下reducer,参数state, action 返回值newState
      // 这就是dispatch一个action可以改变全局state的原因
      currentState = currentReducer(currentState, action)
    } finally {
      // 最终执行, isDispatching标记为false, 即完成状态
      isDispatching = false
    }

    // 监听队列
    // 所有的的监听函数赋值给 listeners
    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      // 执行每一个监听函数
      listener()
    }
    // 返回传入的action
    return action
    // 到这里dispatch方法就结束了, 我们来思考总结一下, 为什么要用listeners
    // 当dispatch发送一个规范的action时,会更新state
    // 但是state改变了之后我们需要做一些事情, 比如更新ui既数据驱动视图
    // (当然一般我们使用react,react-redux的时候, 他们会帮我们完成这些事情)
    // 所以要提供一个监听模式,当然还要有一个监听函数subscribe, 保证dispatch和subscribe之间的一对多的模式
  }

  // 这是一个高级的api, 用于替换计算 state的reducer,不知道的同学面壁去
  // 哈哈开玩笑的确实很不常用, 官网也没怎么介绍
  // redux 热加载机制的时候用到了
  function replaceReducer(nextReducer) {
    // 既然是替换reducer, 类型要保持一直,不是function的滚远点
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }

    // 当前的currentReducer更新为参数nextReducer
    currentReducer = nextReducer
    // 和INIT的dispath相同,发送一个dispatch初始化state,表明一下是REPLACE
    // 自己👀看一下utils方法的ActionTypes, 随性的随机数
    dispatch({ type: ActionTypes.REPLACE })
  }

  // 不知道是干什么的, 先看看哪里用到了, 全局收索一下
  // 我TM!只有这一个地方有这个函数,而且没被使用( [?observable]: observable ), 就问你气不气?
  // 当然不气, 作为不思进取的我觉得不用看这部分了, 算了,简单的过一下, 刚好也不知道?observable这个私有属性的作用
  // 好了, 全局搜索一下?observable, 尼玛,对于我这种码农来说, 貌似又是没用的
  // 好吧,我们看一下作者的注释和代码
  function observable() {
    const outerSubscribe = subscribe
    // 
    return {
      /**
       * The minimal observable subscription method.
       * @param {Object} observer Any object that can be used as an observer.
       * The observer object should have a `next` method.
       * @returns {subscription} An object with an `unsubscribe` method that can
       * be used to unsubscribe the observable from the store, and prevent further
       * emission of values from the observable.
       */
      // 参数明显是object
      subscribe(observer) {
        if (typeof observer !== 'object' || observer === null) {
          throw new TypeError('Expected the observer to be an object.')
        }
        //获取观察着的状态
        function observeState() {
          // 如果有next方法,吧回调state
          if (observer.next) {
            observer.next(getState())
          }
        }

        observeState()
        //返回取消订阅的方法
        const unsubscribe = outerSubscribe(observeState)
        return { unsubscribe }
      },

      [?observable]() {
        return this // 猜测this应该是store
      }
      // observable方法简单过一下,不做过多解释,有了解的同学,欢迎不吝赐教
    }
  }

  // 有没有想过,在使用redux的时候, 初始化的state哪来的
  // 当然是自己先dispatch了一下
  //reducer 返回其初始状态 
  //初始化 store 里的 state tree
  dispatch({ type: ActionTypes.INIT })

  // 这个就是返回的store嘛
  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [?observable]: observable
  }
}
复制代码

看完createStore,已经对redux的大体实现有了一定的了解, 接下来我们看combineReducers

先过一下文件最吸引我的是export default function combineReducers,其他几个function好像都是用来抛出一些warning的, 所以先看这个combineReducers function(上面的先不要看👀,直接找combineReducers )

import ActionTypes from './utils/actionTypes'
import warning from './utils/warning'
import isPlainObject from './utils/isPlainObject'

/**
 *  先过一下文件最吸引我的是export default function combineReducers
 *  先看这个combineReducers function
 * 
 */
function getUndefinedStateErrorMessage(key, action) {
  const actionType = action && action.type
  const actionDescription =
    (actionType && `action "${String(actionType)}"`) || 'an action'

  return (
    `Given ${actionDescription}, reducer "${key}" returned undefined. ` +
    `To ignore an action, you must explicitly return the previous state. ` +
    `If you want this reducer to hold no value, you can return null instead of undefined.`
  )
}

function getUnexpectedStateShapeWarningMessage(
  inputState,
  reducers,
  action,
  unexpectedKeyCache
) {
  const reducerKeys = Object.keys(reducers)
  const argumentName =
    action && action.type === ActionTypes.INIT
      ? 'preloadedState argument passed to createStore'
      : 'previous state received by the reducer'

  if (reducerKeys.length === 0) {
    return (
      'Store does not have a valid reducer. Make sure the argument passed ' +
      'to combineReducers is an object whose values are reducers.'
    )
  }

  if (!isPlainObject(inputState)) {
    return (
      `The ${argumentName} has unexpected type of "` +
      {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] +
      `". Expected argument to be an object with the following ` +
      `keys: "${reducerKeys.join('", "')}"`
    )
  }

  const unexpectedKeys = Object.keys(inputState).filter(
    key => !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key]
  )

  unexpectedKeys.forEach(key => {
    unexpectedKeyCache[key] = true
  })

  if (action && action.type === ActionTypes.REPLACE) return

  if (unexpectedKeys.length > 0) {
    return (
      `Unexpected ${unexpectedKeys.length > 1 ? 'keys' : 'key'} ` +
      `"${unexpectedKeys.join('", "')}" found in ${argumentName}. ` +
      `Expected to find one of the known reducer keys instead: ` +
      `"${reducerKeys.join('", "')}". Unexpected keys will be ignored.`
    )
  }
}

function assertReducerShape(reducers) {
  Object.keys(reducers).forEach(key => {
    const reducer = reducers[key]
   // reducer返回值
    const initialState = reducer(undefined, { type: ActionTypes.INIT })
    // undefined throw Error
    if (typeof initialState === 'undefined') {
      throw new Error(
        `Reducer "${key}" returned undefined during initialization. ` +
          `If the state passed to the reducer is undefined, you must ` +
          `explicitly return the initial state. The initial state may ` +
          `not be undefined. If you don't want to set a value for this reducer, ` +
          `you can use null instead of undefined.`
      )
    }

    // 很明显assertReducerShape是用于reducer的规范
    // 回到combineReducers
    if (
      typeof reducer(undefined, {
        type: ActionTypes.PROBE_UNKNOWN_ACTION()
      }) === 'undefined'
    ) {
      throw new Error(
        `Reducer "${key}" returned undefined when probed with a random type. ` +
          `Don't try to handle ${
            ActionTypes.INIT
          } or other actions in "redux/*" ` +
          `namespace. They are considered private. Instead, you must return the ` +
          `current state for any unknown actions, unless it is undefined, ` +
          `in which case you must return the initial state, regardless of the ` +
          `action type. The initial state may not be undefined, but can be null.`
      )
    }
  })
}

// 用于合并reducer 一般是这样combineReducers({a,b,c})
export default function combineReducers(reducers) {
  // reducers中key的数组
  const reducerKeys = Object.keys(reducers)
  // 最终的reducer
  const finalReducers = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    // 接受当前的key
    const key = reducerKeys[i]

    // 如果不是生产环境, 当前的reducer是undefined会给出warning
    if (process.env.NODE_ENV !== 'production') {
      if (typeof reducers[key] === 'undefined') {
        warning(`No reducer provided for key "${key}"`)
      }
    }

    // reducer要是一个function
    if (typeof reducers[key] === 'function') {
      // 赋值给finalReducers
      finalReducers[key] = reducers[key]
    }
    // 循环结束, 目的为了给finalReducers赋值, 过虑了不符合规范的reudcer
  }
  // 符合规范的reducer的key数组
  const finalReducerKeys = Object.keys(finalReducers)

  // 意想不到的key, 先往下看看
  let unexpectedKeyCache
  if (process.env.NODE_ENV !== 'production') {
    // production环境为{}
    unexpectedKeyCache = {}
  }

  let shapeAssertionError

  try {
    // 看这个function
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }

  // 返回function, 即为createstore中的reducer参数既currentreducer
  // 自然有state和action两个参数, 可以回createstore文件看看currentReducer(currentState, action)
  return function combination(state = {}, action) {
    // reducer不规范报错
    if (shapeAssertionError) {
      throw shapeAssertionError
    }

    // 比较细致的❌信息,顺便看了一下getUndefinedStateErrorMessage,都是用于提示warning和error的, 不过多解释了
    if (process.env.NODE_ENV !== 'production') {
      const warningMessage = getUnexpectedStateShapeWarningMessage(
        state,
        finalReducers,
        action,
        unexpectedKeyCache
      )
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    let hasChanged = false
    const nextState = {}
    for (let i = 0; i < finalReducerKeys.length; i++) {
      // 获取finalReducerKeys的key和value(function)
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      // 当前key的state值
      const previousStateForKey = state[key]
      // 执行reducer, 返回当前state
      const nextStateForKey = reducer(previousStateForKey, action)
      // 不存在返回值报错
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      // 新的state放在nextState对应的key里
      nextState[key] = nextStateForKey
      // 判断新的state是不是同一引用, 以检验reducer是不是纯函数
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    // 改变了返回nextState
    return hasChanged ? nextState : state
  }
  /*
  *  新版本的redux这部分改变了实现方法
  *  老版本的redux使用的reduce函数实现的
  *  简单例子如下
  * function combineReducers(reducers) {
  *    return (state = {}, action) => {
  *        return Object.keys(reducers).reduce((currentState, key) => {
  *            currentState[key] = reducers[key](state[key], action);
  *             return currentState;
  *         }, {})
  *      };
  *    }
  * 
  * */
}

复制代码

到这里,似乎已经基本熟悉了redux的核心, 不过别急,还有重要的applyMiddleware, 哈哈, 先看下bindActionCreator.js缓缓

想必有点同学还不知道这个api,我先看看bindActionCreators作用, 熟悉的同学直接看实现

/**
 *
 * @export
 * @param {*} actionCreators  一个 action creator,或者一个 value 是 action creator 的对象。
 * @param {*} dispatch 一个由 Store 实例提供的 dispatch 函数。
 * @returns 一个与原对象类似的对象,只不过这个对象的 value 都是会直接 dispatch 原 action creator 返回的结果的函数。
 *          如果传入一个单独的函数作为 actionCreators,那么返回的结果也是一个单独的函数。
 * 
 * 场景: 惟一会使用到 bindActionCreators 的场景是当你需要把 action creator 往下传到一个组件上,
 *        却不想让这个组件觉察到 Redux 的存在,而且不希望把 dispatch 或 Redux store 传给它。
 * /
复制代码

bindActionCreator的实现

function bindActionCreator(actionCreator, dispatch) {
  // 闭包
  return function() {
    // 执行后返回结果为传入的actionCreator直接调用arguments
    return dispatch(actionCreator.apply(this, arguments))
  }
}
// 先看这里 🔥🔥🔥
export default function bindActionCreators(actionCreators, dispatch) {
  // actionCreators为function
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }

  // 不是object throw Error
  if (typeof actionCreators !== 'object' || actionCreators === null) {
    throw new Error(
      `bindActionCreators expected an object or a function, instead received ${
        actionCreators === null ? 'null' : typeof actionCreators
      }. ` +
        `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
    )
  }

  // object 转为数组
  const keys = Object.keys(actionCreators)
  // 定义return 的props
  const boundActionCreators = {}
  for (let i = 0; i < keys.length; i++) {
    // actionCreators的key 通常为actionCreators function的name(方法名)
    const key = keys[i]
    // function => actionCreators工厂方法本身
    const actionCreator = actionCreators[key]
    if (typeof actionCreator === 'function') {
      // 参数为{actions:function xxx}是返回相同的类型
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
    }
  }
  // return 的props
  return boundActionCreators
}
复制代码

最后,我们看一下applyMiddeware.js

等等, 先解释一下compose, 函数编程中的方法

 Composes functions from right to left.
复制代码

组合函数,将函数串联起来从右到左执行 这里的import compose from './compose'可能就是从函数编程移过来的

涨这样:
compose(funcA, funcB, funcC) === compose(funcA(funcB(funcC())))
复制代码
 import compose from './compose'

/***
 * 
 * middleware既中间件,简单说在redux中作为扩展 dispatch 的唯一标准的方式。
 * 不熟悉的同学自行去api了解一下, 大致结构是这样的
 *  middleware = (store) => (next) =>(action) =>{ [return next(action)]}
 *  为了方便debugger我们先自己写一个简单的logger middleware,看->src/index.js
*/
// applyMiddleware用来添加中间件,在修改数据的时候redux通过改造dispatch来实现中间件.
// 来吧,揭开applyMiddleware的神秘面纱
export default function applyMiddleware(...middlewares) {
  // 返回一个名为createStore的function
  // 不知道你还是否记得createStore.js开头的这段代码
  /*
    if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    return enhancer(createStore)(reducer, preloadedState)
    }
    嗯哼?对上了吧, 有applyMiddleware的时候直接先执行这里, 没绕过来的同学debugger一下
  * */
  // 直接return createStore function
  // 这里我们看下执行顺序, 我们写一点伪代码,每一个变量是代码中debugger的位置
  /**
   *   createStore.js 
   *   d1 = createStore(reducer, initstate, enhancer){ ... debugger if (typeof enhancer !== 'undefined')}
   * 
   *   d2 =  if (typeof enhancer !== 'undefined') {
                      if (typeof enhancer !== 'function') {
                        throw new Error('Expected the enhancer to be a function.')
                      }
                      debugger
                    return enhancer(createStore)(reducer, preloadedState)
                    }
   *   d3 = if (typeof enhancer !== 'undefined') {} debugger
   *   
   *   d4 =  ... debugger const middlewareAPI = {
                      // copy getState
                      getState: store.getState,
                      dispatch: (...args) => dispatch(...args)
                    }
      
        d5 =    ... debugger  const store = createStore(...args)...
   *   
   *   执行顺序
   *   创建store的首先是调用createStore(...applyMiddleware()) 大致发生了这样的流程
   *   createStore(...applyMiddleware()) -> applyMiddleware() -> return function -> d1 -> d2 
   *   接下来
   *   return enhancer(createStore)(reducer, preloadedState) -> d5 -> createStore(...args)再次调用createStore -> d1
   *   接下来走d3下面的store初始化 -> dispatch(init) -> d4 -> 组合middleware,合并new dispatch -> 返回增强的store
   */
  return createStore => (...args) => {
    // 保存createStore(reducer, initstate) || createStore(reducer), 赋值给store
    // debugger
    const store = createStore(...args)
    // 定义了一个dispatch, 调用会 throw new Error(dispatching虽然构造middleware但不允许其他middleware应用 )
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }
    // debugger
    // 定义middlewareAPI, 中间件中的store  eg ->  logger(store)
    const middlewareAPI = {
      // add getState
      getState: store.getState,
      // 添加dispatch并包装一个function, 参数为(reducer, [initstate])
      // 向下看一看middlewareAPI作为参数被回调回去,不难理解, 告诉dispath不能再middleware插件中构造
      dispatch: (...args) => dispatch(...args)
    }
    // 调用每一个这样形式的middleware = store => next => action =>{}, 
    // 组成一个这样[f(next)=>acticon=>next(action)...]的array,赋值给chain
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // debugger
    // compose看 -> compose.js文件
    // compose(...chain)会形成一个调用链, next指代下一个函数的注册, 这就是中间件的返回值要是next(action)的原因
    // 如果执行到了最后next就是原生的store.dispatch方法
    dispatch = compose(...chain)(store.dispatch) 
    // 返回增强的store
    return {
      ...store,
      dispatch
    }
  }
}

复制代码

最后的最后我们去compose.js做一道题

 // 其实这个很有意思,是函数编程中的方法
//  我们来做一到题
//  实现这个样一个function -> compose(funcA, funcB, funcC) 形象为 compose(funcA(funcB(funcC()))))
//  返回值为一个(...args)=>(funcA(funcB(funcC(...args)))))
/**
 *
 * 你可能会这样写, 或者是for循环 
 * 
 *  function Compose(...funcs){
      if (funcs.length === 0) {
        return args => args;
      }
      if (funcs.length === 1) {
        return funcs[0]
      }
      const arr = funcs;
      let firstFun = arr[0];
      let len = arr.length;
      let i = 1;
      while(i !== len) {
        firstFun = firstFun(arr[i]);
        i++;
      }
      return firstFun;
    }
 * 
 * 
 */
// 好啦, 我们看看优秀的答案吧 👇

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  // 是不是很巧妙
  // 其实compose是redux作者从函数式编程中移过来的, 有兴趣的同学去了解一下
  // 插个话, 因为compose的执行顺序原因, 所以有的middleware插件会要求要放在最后面
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
复制代码

好了,到这里我们就把redux的源码看完了

笔者觉得redux源码并没有很难,主要的精华是他的实现思想,我们在来看看redux的三大原则

1.整个应用的state存储在store中,有且只存在一个store。

2.store里面的state是只读的,唯一改变state的方法就是派发(dispatch)一个动作(action)。

3.纯函数(reducer)修改state,每次返回一个新的state,不能直接修改原对象。

下一次,我们来分析一下这样做的好处

以及我们可不可以自己写一个简单的redux

第一次写博客, 居然这么累😫, 以后会坚持更新分享, O(∩_∩)O谢谢各位看官老爷, 欢迎交流,分享,指导。

附上github地址

文章分类
前端
文章标签