redux之applymiddleware

自己也有一些疑问:为什么redux-thunk被称为中间件?

为什么用到redux-thunk、redux-logger的时候要用applymiddleware

带着疑问写下了这篇短文;希望能帮助我理解applymiddleware。

现在有个需求

现在有函数f1,f2,f3,希望f3执行时,f1,f2也执行

image.png

解决这个需求
看当前需求,很简单啊,执行f3的时候,同时执行f1,f2不就行了;


function f1() {
  console.log('f1函数???')
}

function f2() {
  console.log('f2函数执行了??')
}

function f3() {
  f1()
  f2()
  console.log('todo')
}
复制代码

需求变更了

增加 函数log打印一些数据;
希望f3执行时,f1,f2,log函数执行


function f1() {
  console.log('f1函数???')
}

function f2() {
  console.log('f2函数执行了??')
}

function log(){
    console.log('打印一些数据')
}

function f3() {
  f1()
  f2()
  log()
  console.log('todo')
}
复制代码

在f3中执行f1、f2、log函数的问题逐渐显现了,不利于开发者理解和维护;

并且每新增一个函数都要修改一遍f3代码,不符合影响最小原则;

如果f1,f2需要参数呢?哪还是需要修改f3代码的,要在f3调用f1、f2、的地方将参数传入;

函数少了还好,调用的函数多了,难免出错;

有什么方法,既可以实现需求,又可以解耦f3与f1、f2、log...函数呢?

applymiddleware

让applymiddleware处理f1、f2、log....等函数;

首先改写f3

function f1() {
  console.log('f1函数???')
}

function f2() {
  console.log('f2函数执行了??')
}

function f3(enhancer) {

   //如果有参数传入,执行参数
  if (enhancer) {
    return enhancer(f3)
  }
  //没有参数传入,执行原f3函数
  return function () {
    console.log('todu')
  }
}

const start = f3()
//这里执行start类似执行原来f3()
start()
复制代码

开始写applymiddleware函数

跟着备注走,备注有标号

// 现在有函数f1,f2,f3,希望f3执行时,f1,f2也执行

function f1() {
  console.log('f1函数???')
}

function f2() {
  console.log('f2函数执行了??')
}
function log() {
  console.log('打印一些数据')
}
function f3(enhancer) {
  //1、如果有参数传入,执行参数
  if (enhancer) {
    // 7、这里执行了一个函数有入参f3,说明enhancer返回了一个函数
    return enhancer(f3)
  }
  //2、没有参数传入,执行原f3函数
  return function () {
    console.log('todu')
  }
}

// 5、调用中间件
const start = f3(applyMiddleware(f1, f2, log))
//3、这里执行start类似执行原来f3()
start()

//4、中间件函数
function applyMiddleware(...middlewares) {
  // 6、因为中间要执行的函数数量不确定,这里用...展开符

  // 8、根据备注7、这里应该返回一个函数是不是?可以理解吧,并且还要接收参数f3
  return function (f3) {
    // 9、middlewares是一个数组,可以理解吧?数组里面放的是f1、f2、log函数可以理解吧
    // 10、数组是可以使用map的对吧,现将f1、f2、log这些函数执行一下
    const chain = middlewares.map((fn) => fn())

    // 11、将f1,f2,log合并执行一遍,并将f3函数传入
    const f = compose(...chain)(f3)

    //17、将合并好的函数返回回去
    return f()
  }
}

function compose(...funcs) {
  //12、因为不知道要合并集合函数,所以要用...展开符
  // 13、如果没有数组传来,将参数传递出去
  if (funcs.length === 0) return (args) => args

  // 14、只有一个函数,直接执行
  if (funcs.length === 1) return funcs[0]

  //15、函数数量超出1个,使用reduce,因为funcs是数组,这可以理解吧
  // 16、 args是外面传递过来的参数,这里是f3
  return funcs.reduce(
    (a, b) =>
      (...args) =>
        a(b(...args))
  )
}

复制代码

applyMiddleware

// 现在有函数f1,f2,f3,希望f3执行时,f1,f2也执行

function f1() {
  // 18、根据备注15、可以知道f1必然有入参,且入参是函数、且必然返回的是函数
  return function (next) {
    return function () {
      console.log('f1函数???1')

      return next()
    }
  }
}

function f2() {
  // 19、根据备注15、可以知道f1必然有入参,且入参是函数、且必然返回的是函数
  return function (next) {
    return function () {
      console.log('f2函数???')
      return next()
    }
  }
}
function log() {
  // 20、根据备注15、可以知道f1必然有入参,且入参是函数、且必然返回的是函数
  return function (next) {
    return function () {
      console.log('log函数')
      return next()
    }
  }
}
function f3(enhancer) {
  //1、如果有参数传入,执行参数
  if (typeof enhancer === 'function') {
    // 7、这里执行了一个函数有入参f3,说明enhancer返回了一个函数
    return enhancer(f3)
  }
  //2、没有参数传入,执行原f3函数,option是参数
  return function (option) {
    console.log('todu', option) //输出todu 这里是啥?
  }
}

// 5、调用中间件
const start = f3(applyMiddleware(f1, f2, log))
// console.log('start', start)
//3、这里执行start类似执行原来f3()
start({ type: '这里是啥?' })

//4、中间件函数
function applyMiddleware(...middlewares) {
  // 6、因为中间要执行的函数数量不确定,这里用...展开符

  // 8、根据备注7、这里应该返回一个函数是不是?可以理解吧,并且还要接收参数f3
  return function (f3) {
    // 9、middlewares是一个数组,可以理解吧?数组里面放的是f1、f2、log函数可以理解吧
    // 10、数组是可以使用map的对吧,现将f1、f2、log这些函数执行一下
    const chain = middlewares.map((fn) => fn())

    // 11、将f1,f2,log合并执行一遍,并将f3函数传入
    const f = compose(...chain)(f3)

    // console.log('ff', f)
    //17、将合并好的函数返回回去

    return f()
  }
}

function compose(...funcs) {
  //12、因为不知道要合并集合函数,所以要用...展开符
  // 13、如果没有数组传来,将参数传递出去
  if (funcs.length === 0) return (args) => args
  console.log('funcs', funcs[0])
  // 14、只有一个函数,直接执行
  if (funcs.length === 1) return funcs[0]

  //15、函数数量超出1个,使用reduce,因为funcs是数组,这可以理解吧
  // 16、 args是外面传递过来的参数,这里是f3
  return funcs.reduce(function (a, b) {
    return function (...args) {
      return a(b(...args))
    }
  })
}


复制代码

哈哈,完整的applymiddleware

function applyMiddleware(...middlewares) {
  //返回第一个函数,函数的参数是createStore
  return function (createStore) {
    //返回了第二层函数,函数的参数是reduer
    return function (reducer) {
      //获取原始store
      const store = createStore(reducer)

      //获取当前原始dispatch
      let dispatch = store.dispatch

      const middleAPI = {
        dispatch: (action, ...args) => dispatch(action, args),
        getState: store.getState,
      }

      // 得到了一个有中间件组成的函数数组;
      const chian = middlewares.map((middleware) => middleware(middleAPI))

      // 将中间件执行的结果返回给dispatch;在调用dispatch的时候使用的就是增强后的dispatch了
      dispatch = compose(...chian)(store.dispatch)
      console.log('dispatch', dispatch)
      return {
        ...store,
        dispatch,
      }
    }
  }
}

function compose(...funcs) {
  if (funcs.length === 0) return (args) => args
  if (funcs.length === 1) return funcs[0]
  return funcs.reduce(
    (a, b) =>
      (...args) =>
        a(b(...args))
  )
}

复制代码

纯属个人理解,但是还没有理解透测,仅记此文,记录学习历程;后续完善

猜你喜欢

转载自juejin.im/post/7032293232591503390