1
| 中间件其实不仅仅是Redux专利,在Node框架中也有应用,比如koa,这里我们简单的默认为Redux 中间件,在进入正题前,先了解一下面向切面编程中件的关系 一、中间件与面向切面编程(AOP) 面。..
|
中间件其实不仅仅是
Redux
专利,在
Node
框架中也有应用,比如
koa
,这里我们简单的默认为
中间件,在进入正题前,先了解一下面向切面编程与中间件的关系
一、Redux中间件原理
1.1 中间件与面向切面编程(AOP)
面向切面编程(AOP)的存在,解决了我们熟悉的面向对象(OOP)的局限性,可以将其看作是OOP的补充。比如当我们要为某几个类新增一段共同的逻辑,在OOP模式下,即可通过修改它们共同的父类来实现,但这无疑使得公共类越来越臃肿。那如果换成AOP,则可将 扩展逻辑在工作流中的执行节点视为一个单独“切点”,形成一个可以拦截前序逻辑的“切面”。
1 2 3 4
| 假设一个通用性很强,业务性很弱的日志追溯需求:要求在每个 `Action` 被派发后,打出一个 `console.log`
|
记录这个动作,面向切面编程(AOP)会如何处理? 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 可见,“切面”与业务逻辑是分离的,通过“即插即用”的方式自由的组织自己想要扩展的功能(异步工作流、性能打点、日志追溯等),它是典型的“非侵入式”的逻辑扩展思路,提升了组织逻辑的灵活度与干净度,规避逻辑冗余、逻辑耦合的问题。 #### 1.2 二、中间件的引入 通过分析了Redux源码的主流程,我们可以肯定 `redux` 源码只有同步操作,也就是当 `dispatch action` 时, `state` 会被立即更新。若需要引入异步数据流,Redux官方则建议使用中间件来增强 `createStore` 的能力,它对外暴露了 `applyMiddleware` 函数,接受任意个中间件作为入参,返回作为 的入参的值 ```sql // 引入 redux import { createStore } from 'redux' // 创建 store const store = createStore( reducer, initial_state, applyMiddleware(middleware1, middleware2, ...) );
|
1.3 三、中间件的机制
我们顺着中间件引入的角度,简单提取一下
源码框架,更加深刻的理解
是如何与
配合工作的?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| function applyMiddleware(...middlewares) {
return createStore => (...args) => { const store = createStore(...args) let dispatch = () => { throw new Error(`Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.`) } ......下面代码依次放在此处...... }
`当```text dispatch action `时,```text action `必须是一个普通对象,但使用过中间件的同学会发现```text `是允许为函数的,这背后```text applyMiddleware `是如何改写```text dispatch
|
函数的?
1、以
middlewareAPI
作为中间件的入参,逐个调用传入的中间件,获取一个由“内层函数”组成的数组
chain
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI))
`2、调用```text compose `函数,将```text chain `中的 “内层函数” 逐个组合起来,并调用最终组合出来的函数,传入```text `作为入参```java dispatch = compose(...chain)(store.dispatch)
`3、返回一个新的```text store `对象,这个```text store `对象的```text `已经被改写过了```java return { ...store, }
`最后,我们深剖一下函数式编程中一个通用的概念,函数合成(```text `函数)```java function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) }
|
reduce
会将数组中的每个元素执行指定的逻辑,并将结果汇总为单个返回值,假设有这样一个
compose
1
| 调用 `compose(f1,f2,f3,f4)` 函数会被组合成这样的形式 `(...args) => f1(f2(f3(f4(...args))))` 即
|
f1,f2,f3,f4
这4个中间件的内层逻辑会被组合到一个函数中去,当这个函数被调用时,中间件会依次被调用
1.4 四、中间件的工作模式
从中间件的机制中,我们知道 任何的中间件都可以用自己的方式解析
dispatch
的内容,并继续传递
actions
给下一个中间件。但注意:当最后一个中间件开始
时,
action
必须是一个普通对象,因为这是同步式的
数据流 开始的地方。
1、redux-thunk源码解析
我们以为例,探究下中间件的工作模式 接下来,我们透过redux-thunk中间件的源码分析,验证上面的结论:
1 2 3
| function extraArgument) { return ({ dispatch, getState }) => (next) => (action) => {
|
1 2 3
| if (typeof action === 'function') { return action(dispatch, getState, extraArgument);
|
}
1 2
| // 若 action 不是一个函数,则不处理,直接放过 return next(action);
|
};
1 2
| const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware;
|
从```text redux-thunk源码层面可知道,它主要做的一件事就是 拦截到```text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| 后,检查它是否是一个函数 若是函数,则执行它并返回执行的结果 若不是函数,则直接调用 `next` ,工作流继续往下走 ##### 2、redux-thunk 模拟付款请求 现在,我们假设有这样一个需求:我们需要感知每一次付款请求的发送和响应,并处理请求的结果 引入 import axios from 'axios' import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import reducer from './reducers';
applyMiddleware(thunk) );
`dispatch 一个 action,action 是一个函数```java store.dispatch(payMoney(payInfo));
`payMoney 的返回值是一个函数```java // 支付信息 const payInfo = { userName: huamu, password: xxx, count: 1000000 }
const payMoney = (payInfo) => (dispatch) => { // 付款前发出准备信号 dispatch({ type: 'payStart' })
fetch().then(res => { dispatch()})
return axios.post('/API/payMoney', {payInfo}) .then(function (response) { console.log(response); // 付款成功信号 dispatch({ type: 'paySuccess' }) }) .catch(function (error) { console.log(error); // 付款失败信号 dispatch({ type: 'payError' }) });
`##### 3```text Redux
|
的工作流

结合上面的分析,中间件的工作模式有如下两点可掌握
中间件的执行时机:在
被分发之后、
reducer
触发之前
中间件的执行前提:
函数对
函数进行改写,使得
触发
之前,执行
中间件的链式调用。
本文标题: Redux中间件到底怎么
发布时间: 2023年01月27日 00:00
最后更新: 2025年12月30日 08:54
原始链接: https://haoxiang.eu.org/6fafd0ad/
版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0许可协议,转载请注明出处!