参考:https://juejin.im/post/5b627b...
参考:https://segmentfault.com/a/11...

前言

redux是什么?在Redux中文指南中是这样描述的:Redux是JavaScript状态容器,提供可预测的状态管理。为什么开始分析redux的源码呢?第一让自己更加深入的了解一波redux的原理和实现机制。第二就是redux源码比较少,比较容易理解。其他难的源码我也看不懂,嘻嘻。

MVC

为什么要要要在redux源码解析中提到MVC呢?主要是看到另外一个博主写的,感觉比较受用,所以借鉴过来了~
什么是MVC? MVC是一种设计模式,它将应用分为了三个部分,M(数据模型层,数据保存),V(视图层,用户界面),C(控制器层,业务逻辑)。

一个事件的发生可以理解成这样:
1.用户从view层和应用发起交互;
2.在控制器(controller)中的事件处理器被触发;
3.控制器从Modal层中请求数据,并交给view;
4.view层进行视图的展示;

借用一张图:

clipboard.png

但是在实际项目中,例如backbone.js中的实现。虽然没有用过...看了下阮老师的MVC介绍中有这块,如图:

clipboard.png

可以从图中看到:
1.view和model的双向箭头,view可以直接触发model的改变然后在视图展现;
2.用户可以直接触发controller(改变 URL 触发 hashChange 事件),然后controller直接发送给view;
这样在数据量庞大的前提下可能会出现以下情况(夸张情况):

clipboard.png

既然是说要源码解析,那么我们首先看下源码结构~如下图:

clipboard.png

applyMiddleware.js、bindActionCreator.js、combineReducer.js、compose.js、createStore.js这几个文件是redux中的核心文件也是核心的几个方法。我们来一个一个的看看。

1. createStore.js

createStore是干嘛的?

createStore接受3个参数:

reducer,是一个纯函数,这里不做多的解释。
preloadedState,可选参数,设置初始state,在同构应用中可以把服务端的state注水给他。
enhancer ,可选参数,是一个组合store的高阶函数,返回一个新的增强store,和middleware 相似,可以通过复合函数改变store接口。

createStore会创建一个store,存放所有的state,在应用中只有一个store。在创建store的时候会默认dispatch一个action。接下来上源码(经过简化的,但是重要的都留下了,嘻嘻):

import $$observable from 'symbol-observable'

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

//createStore接受三个参数
export default function createStore(reducer, preloadedState, enhancer) {

  //判断下preloadedState和enhancer是否存在
  //然后将两个参数值交换的过程
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  //判断enhancer是否是函数类型,如果不是则抛出错误
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    //将createStore当做参数传入通过包装返回,然后再执行无enhancer的createStore方法
    return enhancer(createStore)(reducer, preloadedState)
  }

  //对reducer进行类型判断,如果不是函数类型抛出异常
  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }

  //这里定义了当前的reducer
  let currentReducer = reducer 

  //这里定义了当前的state,然后将初始的state赋值
  let currentState = preloadedState 

   //定义一个数组存放一组监听函数,当state改变后触发,
  let currentListeners = []

  // 这一步干啥的?????还不懂,留着问题,继续往下看!!!
  let nextListeners = currentListeners 

  //应该是用来判断是否正在执行dispatch,有啥用????留着问题,还是继续往下看!!!
  let isDispatching = false 

  //靠,这又是干啥的,感觉和state改变后的监听函数有关系,还是放着吧!!!回头再看
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      //通过slice方法创建一个副本然后赋值给nextListeners
      nextListeners = currentListeners.slice()
    }
  }
  
  //哦,这个知道,store有一个getState方法,用来获取当前的state。
  function getState() {
    //这里做下判断,如果在dispatching则抛出异常
    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.'
      )
    }
    //这里就是返回当前的state了
    return currentState
  }

  //store的subscribe方法,添加一个listener监听函数,用来监听state改变的回调。
  function subscribe(listener) {
    //首先判断是否是函数类型,如果不是则抛出异常
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.')
    }

    //然后判断是否在dispatch,如果是则抛出异常,如果在subscribe中再出发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.'
      )
    }

    //感觉是用来标记啥的,等会瞅瞅!!!(回头看原来是用来标识是否有订阅listener)
    let isSubscribed = true

    //咦。这不是我们在上面看到的一个函数么,它在这里干啥啊?
    //滚动你的鼠标上去看看它的函数体里有啥?
    //哦哦,它是把监听的函数列表保存了一个快照哎;
    ensureCanMutateNextListeners()

    //然后在这里给监听函数快照中添加新的监听函数。
    nextListeners.push(listener)

    //返回一个取消订阅的函数
    return function unsubscribe() {
      //咦,看到这个isSubscribed了,原来是在取消监听函数中使用,
      //通过isSubscribed判断是否订阅了listener,上面isSubscribed
      //在刚进来的时候就标记为true
      if (!isSubscribed) {
        return
      }

      //判断是否在dispatch,如果在则抛出异常
      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表示没有订阅的listener了
      isSubscribed = false

      //这里又要保存一个副本
      ensureCanMutateNextListeners()

      //找到当前的listener,然后删掉~~~
      //是不是看到这里感觉nextListeners和currentListeners有啥用有点疑问,
      //下面是redux文档上关于subsribe的描述,应该可以理解了
      /** 
       * 1.监听器调用 dispatch() 仅仅应当发生在响应用户的 actions 或者特殊的条件限制下(比如: 在 store 有一个特殊的字段时 dispatch action)。虽然没有任何条件去调用 dispatch() 在技术上是可行的,但是随着每次 dispatch() 改变 store 可能会导致陷入无穷的循环。
       * 2.订阅器(subscriptions) 在每次 dispatch() 调用之前都会保存一份快照。当你在正在调用监听器(listener)的时候订阅(subscribe)或者去掉订阅(unsubscribe),对当前的 dispatch() 不会有任何影响。但是对于下一次的 dispatch(),无论嵌套与否,都会使用订阅列表里最近的一次快照。
       * 3.订阅器不应该注意到所有 state 的变化,在订阅器被调用之前,往往由于嵌套的 dispatch() 导致 state 发生多次的改变。保证所有的监听器都注册在 dispatch() 启动之前,这样,在调用监听器的时候就会传入监听器所存在时间里最新的一次 state。
       */
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

  //这里是dispatch
  function dispatch(action) {
    //判断 action 不是普通对象。也就是说该对象由 Object 构造函数创建
    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?'
      )
    }

    //判断 dispahch 正在运行,Reducer在处理的时候又要执行 dispatc
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      //执行当前 Reducer 函数返回新的 state
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    //循环执行listeners
    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    //最后返回一个action对象
    return action
  }

  

  //初始化 store,默认执行dispatch
  dispatch({ type: ActionTypes.INIT })

  return {
    dispatch,
    subscribe,
    getState
  }
}

fsrookie
2.9k 声望256 粉丝

目前很多文章都是摘抄记录其他教程。见谅。


引用和评论

0 条评论