中间件其实不仅仅是Redux专利,在Node框架中也有应用,比如koa,这里我们简单的默认为Redux 中间件,在进入正题前,先了解一下面向切面编程���中��件的关系 一、中间件与面向切面编程(AOP) 面…
中间件其实不仅仅是
1 | Redux |
专利,在
1 | Node |
框架中也有应用,比如
1 | koa |
,这里我们简单的默认为
1 | Redux |
中间件,在进入正题前,先了解一下面向切面编程与中间件的关系
一、中间件与面向切面编程(AOP)
面向切面编程(AOP)的存在,解决了我们熟悉的面向对象(OOP)的局限性,可以将其看作是OOP的补充。比如当我们要为某几个类新增一段共同的逻辑,在OOP模式下,即可通过修改它们共同的父类来实现,但这无疑使得公共类越来越臃肿。那如果换成AOP,则可将 扩展逻辑在工作流中的执行节点视为一个单独“切点”,形成一个可以拦截前序逻辑的“切面”。
假设一个通用性很强,业务性很弱的日志追溯需求:要求在每个
1 | Action |
被派发后,打出一个
1 | console.log |
记录这个动作,面向切面编程(AOP)会如何处理?

可见,“切面”与业务逻辑是分离的,通过“即插即用”的方式自由的组织自己想要扩展的功能(异步工作流、性能打点、日志追溯等),它是典型的“非侵入式”的逻辑扩展思路,提升了组织逻辑的灵活度与干净度,规避逻辑冗余、逻辑耦合的问题。
二、中间件的引入
通过分析了Redux源码的主流程,我们可以肯定
1 | redux |
源码只有同步操作,也就是当
1 | dispatch action |
时,
1 | state |
会被立即更新。若需要引入异步数据流,Redux官方则建议使用中间件来增强
1 | createStore |
的能力,它对外暴露了
1 | applyMiddleware |
函数,接受任意个中间件作为入参,返回作为
1 | createStore |
的入参的值
1 | // 引入 redux |
三、中间件的机制
我们顺着中间件引入的角度,简单提取一下
1 | applyMiddleware |
源码框架,更加深刻的理解
1 | applyMiddleware |
是如何与
1 | createStore |
配合工作的?
1 | // 使用“...”运算符将入参收敛为一个数组 |
当
1 | dispatch action |
时,
1 | action |
必须是一个普通对象,但使用过中间件的同学会发现
1 | action |
是允许为函数的,这背后
1 | applyMiddleware |
是如何改写
1 | dispatch |
函数的?
1、以
1 | middlewareAPI |
作为中间件的入参,逐个调用传入的中间件,获取一个由“内层函数”组成的数组
1 | chain |
1 | const middlewareAPI = { |
2、调用
1 | compose |
函数,将
1 | chain |
中的 “内层函数” 逐个组合起来,并调用最终组合出来的函数,传入
1 | dispatch |
作为入参
1 | dispatch = compose(...chain)(store.dispatch) |
3、返回一个新的
1 | store |
对象,这个
1 | store |
对象的
1 | dispatch |
已经被改写过了
1 | return { |
最后,我们深剖一下函数式编程中一个通用的概念,函数合成(
1 | compose |
函数)
1 | // 利用 ... 运算符将入参收敛为数组格式 |
1 | reduce |
会将数组中的每个元素执行指定的逻辑,并将结果汇总为单个返回值,假设有这样一个
1 | compose |
调用
1 | compose(f1,f2,f3,f4) |
函数会被组合成这样的形式
1 | (...args) => f1(f2(f3(f4(...args)))) |
即
1 | f1,f2,f3,f4 |
这4个中间件的内层逻辑会被组合到一个函数中去,当这个函数被调用时,中间件会依次被调用
四、中间件的工作模式
从中间件的机制中,我们知道 任何的中间件都可以用自己的方式解析
1 | dispatch |
的内容,并继续传递
1 | actions |
给下一个中间件。但注意:当最后一个中间件开始
1 | dispatch action |
时,
1 | action |
必须是一个普通对象,因为这是同步式的
1 | Redux |
数据流 开始的地方。
1、redux-thunk源码解析
我们以为例,探究下中间件的工作模式 接下来,我们透过redux-thunk中间件的源码分析,验证上面的结论:
1 | function createThunkMiddleware(extraArgument) { |
从
1 | redux-thunk |
源码层面可知道,它主要做的一件事就是 拦截到
1 | action |
后,检查它是否是一个函数
若是函数,则执行它并返回执行的结果
若不是函数,则直接调用
1 | next |
,工作流继续往下走
2、redux-thunk 模拟付款请求
现在,我们假设有这样一个需求:我们需要感知每一次付款请求的发送和响应,并处理请求的结果
引入
1 | import axios from 'axios' |
dispatch 一个 action,action 是一个函数
1 | store.dispatch(payMoney(payInfo)); |
payMoney 的返回值是一个函数
1 | // 支付信息 |
3、
1 | Redux |
的工作流
结合上面的分析,中间件的工作模式有如下两点可掌握
中间件的执行时机:在
1 | action |
被分发之后、
1 | reducer |
触发之前
中间件的执行前提:
1 | applyMiddleware |
函数对
1 | dispatch |
函数进行改写,使得
1 | dispatch |
触发
1 | reducer |
之前,执行
1 | Redux |
中间件的链式调用。
本文标题: 推荐系列-Redux 中间件 到底怎么工作的呢-
本文作者: OSChina
发布时间: 2021年04月15日 10:08
最后更新: 2023年06月29日 07:10
原始链接: https://haoxiang.eu.org/f696668e/
版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0许可协议,转载请注明出处!