内容简介:由于一直用业界封装好的如首先简单提下什么是中间件,该部分与下文关系不大,可以跳过。来看眼这个经典的图。
由于一直用业界封装好的如 redux-logger、redux-thunk
此类的中间件,并没有深入去了解过 redux
中间件的实现方式。正好前些时间有个需求需要对 action
执行时做一些封装,于是借此了解了下 Redux Middleware
的原理。
* 中间件概念
首先简单提下什么是中间件,该部分与下文关系不大,可以跳过。来看眼这个经典的图。
不难发现:
- 不使用
middleware
时,在dispatch(action)
时会执行rootReducer
,并根据action
的type
更新返回相应的state
。 - 而在使用
middleware
时,简言之,middleware
会将我们当前的action
做相应的处理,随后再交付rootReducer
执行。
简单实现原理
比如现有一个 action
如下:
function getData() { return { api: '/cgi/getData', type: [GET_DATA, GET_DATA_SUCCESS, GET_DATA_FAIL] } }
我们希望执行该 action
时可以发起相应请求,并且根据请求结果由定义的 type
匹配到相应的 reducer
,那么可以自定义中间件处理该 action
,因此该方法封装成中间件之前可能是这样的:
function dispatchPre(action, dispatch) { const api = action.api; const [ fetching_type, success_type, fail_type] = action.type; // 拉取数据 const res = await request(api); // 拉取时状态 dispatch({type: fetching_type}); // 成功时状态 if (res.success) { dispatch({type: success_type, data: res.data}); console.log('GET_SUCCESS'); } // 失败时状态 if (res.fail) { dispatch({type: fail_type}); console.log('GET_FAIL'); }; } // 调用: dispatchPre(action())
那如何封装成中间件,让我们在可以直接在 dispatch(action)
时就做到这样呢?可能会首先想到改变 dispatch
指向
// 储存原来的dispatch const dispatch = store.dispatch; // 改变dispatch指向 store.dispatch = dispatchPre; // 重命名 const next = dispatch;
截止到这我们已经了解了中间件的基本原理了~
源码分析
了解了基本原理能有助于我们更快地读懂 middleware
的源码。一般我们会这样添加中间件并使用。
createStore(rootReducer, applyMiddleware.apply(null, [...middlewares]))
接下来我们可以重点关注这两个函数 createStore
、 applyMiddleware
CreateStore
// 摘至createStore export function createStore(reducer, rootState, enhance) { ... if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } /* 若使用中间件,这里 enhancer 即为 applyMiddleware() 若有enhance,直接返回一个增强的store对象 */ return enhancer(createStore)(reducer, preloadedState) } ... }
ApplyMiddleware
再看看 applyMiddleware
做了什么, applyMiddleware
函数非常简单,就十来行代码,这里将其完整复制出来。
export default 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.` ) } const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
执行步骤
可以将其主要功能按步骤划分如下:
1、依次执行 middleware
。
将 middleware
执行后返回的函数合并到一个 chain
数组,这里我们有必要看看标准 middleware
的定义格式,如下
export default store => next => action => {} // 即 function (store) { return function(next) { return function (action) { return {} } } }
那么此时合并的 chain
结构如下
[ ..., function(next) { return function (action) { return {} } } ]
2、改变 dispatch
指向。
想必你也注意到了 compose
函数, compose
函数如下:
[...chain].reduce((a, b) => (...args) => a(b(...args)))
实际就是一个柯里化函数,即将所有的 middleware
合并成一个 middleware
,并在最后一个 middleware
中传入当前的 dispatch
。这里再使用一个简单的例子方便大家理解。
// 假设chain如下: chain = [ a: next => action => { console.log('第1层中间件') return next(action) } b: next => action => { console.log('第2层中间件') return next(action) } c: next => action => { console.log('根dispatch') return next(action) } ]
可以发现已经将所有 middleware
串联起来了,于是我在之后执行 dispatch
时,就是一个合并了所有中间件的 dispatchFun
~
最后看一下这时候compose执行返回,如下
dispatch = a(b(c(dispatch))) // 调用dispatch(action) // 执行循序 /* 1. 调用 a(b(c(dispatch)))(action) __print__: 第1层中间件 2. 返回 a: next(action) 即b(c(dispatch))(action) 3. 调用 b(c(dispatch))(action) __print__: 第2层中间件 4. 返回 b: next(action) 即c(dispatch)(action) 5. 调用 c(dispatch)(action) __print__: 根dispatch 6. 返回 c: next(action) 即dispatch(action) 7. 调用 dispatch(action) */
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- express中间件的理解
- 理解 Koa 框架中间件原理
- 如何更好地理解中间件和洋葱模型
- Gin 框架系列(三):换个姿势理解中间件
- Gin框架系列03:换个姿势理解中间件
- 消息中间件面试题:消息中间件的高可用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
D3.js in Action
Elijah Meeks / Manning Publications / 2014-3 / USD 44.99
Table of Contents Part 1: An Introduction to D3 1 An introduction to D3.js 2 Information Visualization Data Flow 3 D ata-Driven Design and Interaction Part 2: The Pillars of Information......一起来看看 《D3.js in Action》 这本书的介绍吧!