浅谈redux 中间件的原理
在使用redux管理异步数据流的时候,我们会使用中间件,以redux-thunk中间件为例,我们做一下分析:
首先是构建store,我们需要以下代码进行揉入中间件的类似creatStore函数的构造:
const loggerMiddleware = createLogger(); const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware,
loggerMiddleware
)(createStore); export default function configureStore(initialState) {
return createStoreWithMiddleware(rootReducer, initialState);
}
在这段代码中,我们用到了
applyMiddleware 函数去将中间件揉入构造store的工厂函数中,
applyMiddleware函数的源码如下所示:
import compose from './compose'
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, initialState, enhancer) => {
var store = createStore(reducer, initialState, enhancer)
var dispatch = store.dispatch
var chain = []
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
先看函数的return,我们通过applyMiddleware构建得到的createStoreWithMiddleware函数其实是这样一个函数
function (reducer, initialState, enhancer){
.......
return {
...store,
dispatch
}
}
而store就是它return出来的这个对象
store的建立流程大致就是这样,但此时store的dispatch方法已经不是原来的dispatch,注意下面的代码:
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
这才是 applyMiddleware 方法的核心,它将每个middleware进行处理,并存入到chain 的数组中,然后调用compose方法对chain数组进行处理,处理出来的返回值就是store的dispatch,也就是我们在业务代码中用到的dispatch
接下来看一下compose方法做了什么:
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
} else {
const last = funcs[funcs.length - 1]
const rest = funcs.slice(0, -1)
return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}
}
它通过调用数组的reduceRight方法对各个中间件进行整合
reduceRight方法的 第一参数是 callback(preValue,curValue) ,第二个参数是要传递给callback作为第一个参数preValue来使用的
这时我们回到applyMiddleware方法中的这段代码:
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
由此我们可以知道传给last(...args)的正是 store.dispatch
我们根据官方文档可以知道中间件的通用构造如下:(箭头函数这里略过)
function middleware({dispatch, getState}) {
return function (next) {
return function (action) {
return next(action);
}
}
}
chain数组里面的数据结构是这样的 :[ function(next){return function(action){...}},function(next){return function(action){...}} ...]
也就是 middleware函数的里面一层 的这个函数
function (next) {
return function (action) {
return next(action);
}
}
然后再经过compose的进一步reduceRight提炼:
return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
compose就是 function(action){return next(action)}
在经过 f(composed) 仍是 function(action){return next(action);} 只不过这里的next是上一个中间件的返回值,追溯源头,next其实就是 store.dispatch一路经过f(composed)这种方式将中间件的方法揉和进来的变种dispatch
所以经过揉入中间件的createStore工厂函数返回的store对象的dispatch方法,其实就是function(action){return next(action);}
然后结合实际中我们使用redux-thunk进行异步数据操作,thunk源码如下:
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
//箭头函数转变正常就是这样
function createThunkMiddleware(extraArgument) {
return function({ dispatch, getState }){
return function(next){
return function(action){
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
}
}
};
}
通过上面分析,我们的store.dispatch就是这个东西
function(action){
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
}
我们在调用异步获取数据的时候 action是这样写的:
export function fetchUri(key){
return function(dispatch){
dispatch(request("show"));
return $.ajax({
url:BOOKLIST_REQ.uri,
dataType:"jsonp",
data:{q:key,count:BOOKLIST_REQ.count}
}).done(res=>{
dispatch(receive(res));
dispatch(request("hidden"));
}).fail(res=>console.error(res));
};
}
激发调取异步数据方法是 store.dispatch(fetchUrl("xxx"));
这样后面的就不用细说了,怎么执行下来就一目了然了吧
这就是整个中间件大致的工作过程,如果有什么说的不对的地方,你特么来打我呀!
浅谈redux 中间件的原理的更多相关文章
- TODO:浅谈pm2基本工作原理
TODO:浅谈pm2基本工作原理 要谈Node.js pm2的工作原理,需要先来了解撒旦(Satan)和上帝(God)的关系. 撒旦(Satan),主要指<圣经>中的堕天使(也称堕天使撒旦 ...
- 浅谈tomcat中间件的优化【转】
今天来总结一下tomcat的一些优化的方案,由于本人才疏学浅,写的不好,勿喷! tomcat对于大多数从事开发工作的童鞋应该不会很陌生,通常做为默认的开发环境来为大家服务,不过tomcat默认的一些配 ...
- 浅谈SpringBoot核心注解原理
SpringBoot核心注解原理 今天跟大家来探讨下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot为什么不需要XML,达到零配置 ...
- 浅谈springboot自动配置原理
前言 springboot自动配置关键在于@SpringBootApplication注解,启动类之所以作为项目启动的入口,也是因为该注解,下面浅谈下这个注解的作用和实现原理 @SpringBootA ...
- redux中间件的原理——从懵逼到恍然大悟
前言react已经出来很久了,其生态圈之庞大,一锅炖不下!各种react-xx,已让我们不堪重负,github上随便一个demo,引入的模块至少都是五指之数+.看着头疼,嚼之无味…….在此建议新学者, ...
- redux中间件的原理
前言react已经出来很久了,其生态圈之庞大,一锅炖不下!各种react-xx,已让我们不堪重负,github上随便一个demo,引入的模块至少都是五指之数+.看着头疼,嚼之无味…….在此建议新学者, ...
- 浅谈 session 会话的原理
先谈 cookie 网络传输基于的Http协议,是无状态的协议,即每次连接断开后再去连接,服务器是无法判断此次连接的客户端是谁. 如果每次数据传输都需要进行连接和断开,那造成的开销是很巨大的. 为了解 ...
- 浅谈JavaScript DDOS 攻击原理与防御
前言 DDoS(又名"分布式拒绝服务")攻击历史由来已久,但却被黑客广泛应用.我们可以这样定义典型的DDoS攻击:攻击者指使大量主机向服务器发送数据,直到超出处理能力进而无暇处理正 ...
- 浅谈HashMap 的底层原理
本文整理自漫画:什么是HashMap? -小灰的文章 .已获得作者授权. HashMap 是一个用于存储Key-Value 键值对的集合,每一个键值对也叫做Entry.这些个Entry 分散存储在一个 ...
随机推荐
- linux下 su 与 su - 的区别和使用
Linux下su与su -命令的区别 在启动服务器ntpd服务时遇到一个问题 使用 su root 切换到root用户后,不可以使用service命令: 使用 su - 后,就可以使用servic ...
- 在Code::Blocks中编译和使用wxWidgets3.0.0教程
跳转至:指南,搜索 注意,编译Code :: Blocks的对wxWidgets的3.0.0链接不是很稳定,但该库至少可以被正确编译,(只是使用的时候可能会有问题):CodeBlocks开发商都在 ...
- spring boot 线程池配置
1.配置类 package cn.com.bonc.util; import java.util.concurrent.Executor; import java.util.concurrent.Th ...
- Ubuntu 和 Windows 之间进行远程访问和文件互传
1. 利用 Ubuntu 自带软件 Remmina 对另一台 Ubuntu 电脑进行远程访问(同一局域网下) 假设要用 A 电脑来控制 B 电脑,首先需要在 B 电脑上进行桌面共享设置 . 然后打 ...
- python 注册表重置ie代理 ss使用后的代理恢复
每次用完ss客户端,浏览器代理都不会改回来,不想手动改,只能用python脚本处理了. import winreg def disableProxy(): proxy = "" x ...
- 网络编程:listen函数
listen函数仅由TCP服务器调用,它做两件事: 当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的客户套接字.listen函数把一个未连 ...
- 【BZOJ 1409】 Password 数论(扩展欧拉+矩阵快速幂+快速幂)
读了一下题就会很愉快的发现,这个数列是关于p的幂次的斐波那契数列,很愉快,然后就很愉快的发现可以矩阵快速幂一波,然后再一看数据范围就......然后由于上帝与集合对我的正确启示,我就发现这个东西可以用 ...
- BZOJ 4777 Usaco2017 Open Switch Grass Kruskal+替罪羊树+权值线段树
这道题首先可以看出答案一定是一条边,而且答案一定在最小生成树上,那么我们就可以在这个最小生成树上维护他与异色儿子的边最小值,所以我们就可以已通过Kruskal和一棵平衡树来解决,时间复杂度是O(n*l ...
- JQuery选择器$()的工作原理浅析
每次申明一个jQuery对象的时候,返回的是jQuery.prototype.init对象,很多人就会不明白,init明明是jQuery.fn的方法啊,实际上这里不是方法,而是init的构造函数,因为 ...
- 使用 URLDecoder 和 URLEncoder 对中文字符进行编码和解码
原文: https://blog.csdn.net/justloveyou_/article/details/57156039 使用 URLDecoder 和 URLEncoder 对中文字符进行编码 ...