ITPub博客

首页 > 大数据 > 数据挖掘 > redux快三源码下载解读

redux快三源码下载解读

原创 数据挖掘 作者:18794834037 时间:2018-08-09 11:59:11 0 删除 编辑

redux  的源码虽然代码量并不多(除去注释大概300行吧)。但是,因为函数式编程的思想在里面体现得淋漓尽致,理解起来并不太容易,所以准备使用三篇文章来分析。

  • 第一篇,快三源码下载dashengba.com(Q3266397597)主要研究  redux  的核心思想和实现,并用100多行的代码实现了其核心功能,相信看完之后,你会完全理解  redux 的核心。这里甩掉  combindReducers  和  applyMiddleware ,不会涉及很高深的柯里化、高阶、归并的思想,但是需要你对闭包有一定的理解。其实, redux  源码本身并不可怕,可怕的是网上太多文章把他和函数式放在一起来分析(装逼)了!!!吓得我们一看到就想跑了。

  • 第二篇, 理解了  redux  的核心之后, 我们会分析  reducers  合并(即  combindReducers )的实现。

  • 第三篇会分析增强器(即  applyMiddleware )的实现,这是最体现函数式风格的地方,并实现一个处理异步请求的  promise  中间件。

在解读  redux  源码之前,我们首先要弄清楚一个问题,就是  redux  和  react-redux  不是同一个东东。  react-redux  是为  react  而定制的,主要是提供  Provider  组件和  connect  方法,方便于我们把  redux  和  react组件  绑定起来。但是,  redux  是没有限制说一定要跟  react  一起使用的。本文只介绍  redux  ,不涉及  react  或者  react-redux  。因为我觉得,如果把  redux  和  react  放在一起讨论,反而会加深了理解的复杂度,分散了我们的注意力,从而影响我们分析源码进度。现在要分析  redux  源码,那就只专注于  redux ,甩开  react  , 就连后面的测试例子,也不要引入  react ,就简单的使用原生html和js测试一下就OK了。

什么是  redux  呢?, 这里也不展开介绍了。就简单的回顾一下  redux  的具体用法:

  1. 定义一个  reducer  函数

  2. 调用  redux.createStore(reducer)  方法创建  store  实例

  3. 通过 store.subscribe(callback)  方法订阅回调事件(即状态变化时会触发回调函数callback)

  4. 通过用户交互(如点击事件)调用  store.dispatch(action) , 改变  store  的状态

可能用些朋友会说,我从来没有用过  store.subscribe 啊,那是因为你使用了  react-redux , 在  connet()  的时候帮你做了这一步。好吧,说好了不扯  react 的。那下面我们就就一步步的来实现  redux  的核心功能吧。

首先来看一下  createStore , 我们平时的用法如下:

const store = createStore(reducer, preloadedState, enhance)

可以接受3个参数,第一个是自定义的 reducer 函数, 第二个是初始状态,第三个是增强器(即  applyMiddleware() 返回的东西),因为前面已经说过了,这里我们不会涉及到  applyMiddleware ,所以,我们的  createStore 只接收2个参数,如下:

function createStore(reducer, preloadedState) {  if (typeof reducer !== 'function') {    throw new Error('Expected the reducer to be a function.')
  }  
  // 定义一些变量,后面几乎所有的方法都会用到,这就是闭包的力量!
  let currentState = preloadedState // state
  let listeners = [] // 订阅事件列表
  let isDispatching = false // 是否正在执行reducer}

createStore  参数和可能会用到的变量定义好了,我们需要实现三个函数,分别是  store.getState  、 store.subscribe  和  store.dispatch 。

首先来实现  store.getState  方法,这个方法没有好说的,就是把闭包里面的  currentState  返回出去就行了,代码如下:

function createStore(reducer, preloadedState) {  // 省略和上面重复的代码
  
  // 获取state
  function getState() {    // 如果正在执行reducer,则抛出异常
    if (isDispatching) {      throw new Error('You may not call store.getState() while the reducer is executing. ')
    }    return currentState;
  }
}

接着我们来实现  store.subscribe 。这个方法是用来添加订阅回调函数的。首先要判断传进来的参数是不是函数类型,然后,把他它push到回调队列(数组)里面。因为可能后面需要把这个回调取消掉,所以还要返回一个方法给外部调用取消,实现代码如下:

function createStore(reducer, preloadedState) {  // 省略和上面重复的代码
  
  // 添加订阅事件
  function subscribe(listener) {    if(typeof listener !== 'function') {      throw new Error('Expected the listener to be a function.')
    }    let isSubscribed = true;
    listeners.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. ');
      }
      isSubscribed = false;      const index = listeners.indexOf(listener);
      listeners.splice(index, 1);
    }
  }
}

最后,我们再来看一下  store.dispatch  方法的实现。  dispatch  接受的参数类型是一个  action  。我们来回顾一下  action 是什么鬼?他要求是一个原生对象,而且必须要有  type  属性,还有可能有  payload  属性。如下是我们的一个用法 :

store.dispatch({  type: 'ADD_SHOPPING',
  payload: 1})

调用 store.dispatch(action) , 它的返回值也是  action 。下面代码是  store.dispatch() 的实现:

function createStore(reducer, preloadedState) {  // 省略和上面重复的代码
  
  function dispatch(action) {    // 如果action不是原生对象,则抛出异常
    // 因为我们期待的action结构为"{type: 'xxx', payload: 'xxx'}"的原生对象
    if(Object.prototype.toString.call(action, null) !== '[object Object]') {      throw new Error('Actions must be plain objects. ');
    }    if(typeof action.type === 'undefined') {      throw new Error('Actions may not have an undefined "type" property. ')
    }    if(isDispatching) {      throw new Error('Reducers may not dispatch actions.')
    }    // 开始调用reducer获取新状态。因为可能会出错需要用try-catch
    // 并且不管成功失败,执行完毕后都要设置isDispatching=true
    try {
      isDispatching = true;
      currentState = reducer(currentState, action);
    } finally {
      isDispatching = false;
    }    // 遍历所有通过store.subscribe()绑定的的订阅事件,并调用他们
    listeners.forEach((listener) => {
      listener();
    })    return action;
  }
}

关于  redux  的分析就写到这里的了。下面是前面分析的代码整合到了一起。

function createStore(reducer, preloadedState) {  if (typeof reducer !== 'function') {    throw new Error('Expected the reducer to be a function.')
  }  let currentState = preloadedState // state
  let listeners = [] // 订阅事件列表
  let isDispatching = false // 是否正在执行reducer
  function getState() {    // 如果正在执行reducer,则抛出异常
    if (isDispatching) {      throw new Error('You may not call store.getState() while the reducer is executing. ')
    }    return currentState;
  }  // 添加订阅事件
  function subscribe(listener) {    if(typeof listener !== 'function') {      throw new Error('Expected the listener to be a function.')
    }    let isSubscribed = true;
    listeners.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. ');
      }
      isSubscribed = false;      const index = listeners.indexOf(listener);
      listeners.splice(index, 1);
    }
  }  function dispatch(action) {    // 如果action不是原生对象,则抛出异常
    // 因为我们期待的action结构为"{type: 'xxx', payload: 'xxx'}"的原生对象
    if(!isPlainObject(action)) {      throw new Error('Actions must be plain objects. ');
    }    if(typeof action.type === 'undefined') {      throw new Error('Actions may not have an undefined "type" property. ')
    }    if(isDispatching) {      throw new Error('Reducers may not dispatch actions.')
    }    // 开始调用reducer获取新状态。因为可能会出错需要用try-catch
    // 并且不管成功失败,执行完毕后都要设置isDispatching=true
    try {
      isDispatching = true;
      currentState = reducer(currentState, action);
    } finally {
      isDispatching = false;
    }    // 遍历所有通过store.subscribe()绑定的的订阅事件,并调用他们
    listeners.forEach((listener) => {
      listener();
    })    return action;
  }  // 将getState, subscribe, dispatch这三个方法暴露出去
  // 创建了store实例之后,可以store.getState()、store.subscripbe()...
  return {
    getState,
    subscribe,
    dispatch
  }
}


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31549408/viewspace-2199504/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2018-08-09

  • 博文量
    1
  • 访问量
    568