资讯专栏INFORMATION COLUMN

浅谈Redux(之一):Middleware原理

cocopeak / 1268人阅读

摘要:作为目前最火的模式实现之一,它有很多的点值得研究。这个函数既然要用于,也就是说它接收一个形式为的函数,对其一层层嵌套形式为。这个会在开始时发起一个,并在这个时发起另一个成功或失败的。为了方便起见,会返回这个让调用者可以等待。

Redux作为目前最火的Flux模式实现之一,它有很多的点值得研究。今天我们首先来看看它的Middleware。

熟悉Express或者koa的朋友对Middleware的概念一定不陌生。例如Express中是这样使用一个中间件的:

var app = express();

app.use(function(req, res, next) {
  console.log("%s %s", req.method, req.url);
  next();
});

app.use中的方法,可以在其后面的http VERB调用之前,对request对象和response对象进行处理,然后通过调用next方法将处理过程转发到下一中间件或者通过返回响应来结束处理过程。(之后有机会的话再写一写NodeExpress)。

我理解的所谓中间件其实就是,通过类似装饰者模式的形式,用代码预处理的方式,保证原本处理问题的函数(或方法)调用不变。

Redux中的中间件可以使得在用户调用store.dispatch之后,先对参数stateactions进行预处理,再让真正的store.dispatch调用,以确保reducer纯度(函数式编程的概念)不变。

Redux中提供了applyMiddleware方法,它的源码只有十几行,真的是非常精妙。

下面我们就研究一下它的源代码。

applyMiddleware方法
applyMiddleware(...middlewares){
    
    return next => (reducer, initialState){
       
        var store = next(reducer, initialState),
            dispatch = store.dispatch,
            chain = [],
            middlewareAPI = {
                getState: store.getState,
                dispatch: (action) => dispatch(action)
            };
            
            chain = middlewares.map(middleware =>
                middleware(middlewareAPI));
            
            dispatch = compose(...chain, store.dispatch);
            
            return {
                ...store,
                dispatch
            }
    }
}

这段代码的意思就是,appleMiddleware方法接收一个Middleware列表,以applyMiddleware(middleware1, middleware2, middleware3)的形式调用(参见ES6的rest参数语法),然后再将创建store的方法传入(我想这个原因是Redux不仅仅可以在React中使用,也可以适用于任何Flux模式的框架和库),然后就会发生神奇的事情。

这两次调用(假设:var newCreateSore = applyMiddleware(middleware1, middleware2)(createStore))会产生一个新的创建Store的方法,但是它改造了原本Store的dispatch方法,让这个dispatch可以做原生dispatch不能做的事情,这样我们就可以订制dispatch的行为,从而实现了中间件的概念。

故而,newCreateStore将作为createStore的替代方法,使用newCreateStore会产生带有中间件的store。

在最内层是如何实现中间件的调用的呢?让我们继续研究。

首先我们用传入的next(一个可以创建Store的函数),创建一个原始的store,并且取出其原生的store.dispatch方法和store.getState方法成为一个对象,作为参数传入中间件函数中,让其第一次包装这个类似store的对象,并返回新的函数。

然后我们使用compose函数,将这些包装过后的返回的函数一个接一个的嵌套调用。

这里补充一下compose的概念:

假设有若干函数f1, f2, f3...,compose指的是类似f1(f2(f3(x)))的调用方式,这在函数式编程中很常见。

(这里的compose函数是redux中的一个方法,这里我们不上它的源码,有兴趣的朋友可以直接看源码。)

被嵌套在compose最内层的是原生的store.dispatch方法,这里我们就一层层的将其包装,在中间件函数中,我们可以利用store的其他方法,比如store.dispatchstore.getState,做一些有意思的事情,比如实现一个记录state改变的日志中间件。

中间件函数

从上面的分析中,我们不难写一个符合要求的中间件函数。

首先中间件函数需要接受一个middlewareAPI,如果使用ES6的语法,这里可以看成是接收一个{dispatch, getState}的形式的参数,这样我们就能在内层使用这两个方法。

接收middlewareAPI参数之后,中间件函数返回另一个函数(为方便后面解释,假设返回的函数为dispatch n)。这个函数既然要用于compose,也就是说它接收一个形式为dispatch的函数,对其一层层嵌套(形式为dispatch1(dispatch2(dispatch3(dispatch))))。在其内部我们可以在之前的dispatch调用之前和之后,进行一些逻辑的处理。

写一个简单的记录state日志的中间件如下:

var middlewareLogger = ({getState}) => next => action => {
    console.log(getState());
    next(action);
    console.log(getState());
}

怎么样,是不是特别简单?

再写一个异步操作的中间件:

const readyStatePromise = store => next => action => {
  if (!action.promise) {
    return next(action)
  }

  function makeAction(ready, data) {
    let newAction = Object.assign({}, action, { ready }, data)
    delete newAction.promise
    return newAction
  }

  next(makeAction(false))
  return action.promise.then(
    result => next(makeAction(true, { result })),
    error => next(makeAction(true, { error }))
  )
}

这个中间件让你可以发起带有一个 { promise } 属性的特殊 action。这个 middleware 会在开始时发起一个 action,并在这个 promise resolve 时发起另一个成功(或失败)的 action。为了方便起见,dispatch 会返回这个 promise 让调用者可以等待。

结束

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90852.html

相关文章

  • Redux中间件与异步Action

    摘要:中间件对异步的实现非常重要,因为在之前的文章中我们谈到,是一个行为抽象,只是一个对象,是一个纯函数,不应该有调用和副作用的操作。这个函数并不需要保持纯净,它还可以带有副作用,包括执行异步请求。那么如何在中进行网络请求标准的做法是使用。 在之前的浅谈Flux架构及Redux实践一文中我们初步的谈及了Redux的数据流思想,并做了一个简单的加减器。但是还没有接触到Redux更多常用的场景,...

    paney129 评论0 收藏0
  • 浅析`redux-thunk`中间件源码

    摘要:大多的初学者都会使用中间件来处理异步请求,其理解简单使用方便具体使用可参考官方文档。源码的源码非常简洁,出去空格一共只有行,这行中如果不算上则只有行。官方文档中的一节讲解的非常好,也确实帮我理解了中间件的工作原理,非常推荐阅读。 总觉得文章也应该是有生命力的,欢迎关注我的Github上的博客,这里的文章会依据我本人的见识,逐步更新。 大多redux的初学者都会使用redux-thunk...

    wing324 评论0 收藏0
  • Redux专题:中间件

    摘要:好处就是不再需要能够处理异步的中间件了。不过,它是一个研究中间件很好的范本。执行它,返回的是由第二层函数组成的中间件数组。也就是说呀同学们,除了最后一个中间件的是原始的之外,倒数往前的中间件传入的都是上一个中间件的逻辑函数。 本文是『horseshoe·Redux专题』系列文章之一,后续会有更多专题推出来我的 GitHub repo 阅读完整的专题文章来我的 个人博客 获得无与伦比的阅...

    ybak 评论0 收藏0
  • redux中间件原理

    摘要:中的是实际的调用顺序是和传入中间件顺序相反的实际的执行是次序是。这个返回的函数是中倒数第二个函数的参数,也就是参数源码参考 showImg(https://segmentfault.com/img/remote/1460000013998406?w=720&h=159); showImg(https://segmentfault.com/img/remote/1460000013998...

    jollywing 评论0 收藏0
  • 十分钟理解Redux中间件

    摘要:最后看一下这时候执行返回,如下调用执行循序调用第层中间件返回即调用第层中间件返回即调用根返回即调用一个例子读懂上文提到是个柯里化函数,可以看成是将所有函数合并成一个函数并返回的函数。 由于一直用业界封装好的如redux-logger、redux-thunk此类的中间件,并没有深入去了解过redux中间件的实现方式。正好前些时间有个需求需要对action执行时做一些封装,于是借此了解了下...

    i_garfileo 评论0 收藏0

发表评论

0条评论

cocopeak

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<