美文网首页
Redux 中间件源码清源

Redux 中间件源码清源

作者: whtoo | 来源:发表于2016-05-09 10:12 被阅读0次

    网上的Redux中间件原理解释多有疏漏,譬如我在多篇blog上看到Redux中间件解释以及Redux中间件深入浅出(译文)前文解释的时候提到了chain,这其实很不准确,因为在applyMiddleWare内部不是按照Chainable call的逻辑实现的,很容易让人误会为middleware1.middleware2...这种错误的逻辑,下文会根据源码进行更正。后者,虽然调用逻辑将的大致对了,但是关于curry function不恰当的引入真的是大大的误导,因为按照curry的逻辑,调用顺序和实际源码中的完全是两个不同方向。

    上面提到的缘起就是我更正的点和踩过的坑。关于middleware内部实现的fn组合和调用顺序的阐述,我凑巧今天早上看到一篇知乎专栏文章Redux middleware 详解,大家可以看,这位兄弟解释的过程和我debug得到的结果是一致的,我也不再赘述。下面,讲一讲,很怪的一个约定,为什么middleware都得习惯性最后

    return next(action)

    以及为何applyMiddleWare内部必须

    dispatch = compose(...chain)(store.dispatch)

    这样才能连接action 和 reducer

    Q1

    针对末尾的return,我只能说这真的只是习惯,因为,你可以在官方的例子real-world中修改api.js和thunk内部的实现,去掉最后的return.这是可以的,为什么呢?原因和Q2有重要关系。因为在Q2的最后enhancer就是通过store.dispatch讲前面处理过的action分发给了reducer。但是,注意这里有一个细节差别,那就是这种处理不是filter chain模式的逐步修改action得到的,而是将action带有的副作用在中间件内部实现消化。换言之,每一个middleware都不是后一个或者前一个的return值提供者。

    仅仅是每个人都处理自己感兴趣的部分,但是都不能修改action,同时根据需要调用next(action)将整个chain继续下去,当然,如果你觉得在某一步出错不用后续处理了,就可以不掉用。

    最后,说一点,所有的dispatch的掉用发端一定是store.dispatch(也就是已经compose(f1,f2,f3..store.orgin_dispatch)),这一步不应该产生返回值,否则我要reducer干嘛。

    Q2 为何最后还是得有原生的store.dispatch,这其实是废话没有这个就没法进行reducer通知合并action更新state了。

    基于上面的论述,我们可以确定两件事情。 第一,middleware中承载的逻辑应该定位为副作用操作,并且不得修改action(但是可以skip)。请记住,不要乱套fp的概念,这个不是monad,本身也不是f1(f2..(..)). 下面的是标准的f1(f2..(..)) ``let f1 = (x) => { x = x + 1 ;return x + 1}

    undefined

    let f2 = (y) => (2 * y)

    undefined

    let f3 = (x) => f1(f2(x))

    undefined

    f3(2)

    6 ``

    然而,在真实的redux里面却是

    | f1                          | 

    |  step process  1     | 

    -------------------- => compose(f1,f2,f3..) 

    |   step process 2      |

    |                  |f2 | | ... | 

    |------------------|

     f1内部先做预处理,然后决定是否call f2,f2内部重复这个过程。

    ## 2016-5-12更新

    第二,middleware中的return next(action) 更准确的应该是 let ret = next(action) -- 官网demo里面 return ret -- 完全不必要 因为 你可以推理 也可以 写console.log加断点跟踪,这些return 最后给谁了? 答案是 store.dispatch(这里的dispatch就是你上面 applyMiddleware增强以后的)。所以,明白了吧,这就是一个常规的嵌套调用,mid1里面 next-》mid2 next->mid3-> ... 这样来的最后的 next(中间件最后)其实 就是 store原生的 dispatch 到这里 我们的action终于给了 reducer。

    第三,通过上面的阐述,我可以给一个自己的结论,那就是middleware的设计定位应该是处理和业务无关的副作用操作(比如 websocket,http,db,log等等),且它也同样适合做 filter(不合法的action我不传递了) 和  interceptor(action 增强比如,你穿入user,我附加上user的扩展信息,然后next给后面)

    ## 2016-5-12 追加更新

    刚刚同事问我上面说的对应源代码中的执行细节,包括但不限于何时是参数绑定,何时是函数执行。我从他的问题里面渐渐意识到,原来

    相关文章

      网友评论

          本文标题:Redux 中间件源码清源

          本文链接:https://www.haomeiwen.com/subject/fmwikttx.html