redux middleware 源码分析
middleware 的由来
在业务中需要打印每一个 action 信息来调试,又或者希望 dispatch 或 reducer 拥有异步请求的功能。面对这些场景时,一个个修改 dispatch 或 reducer 代码有些乏力,我们需要一个可组合的、自由增减的插件机制,Redux 借鉴了 Koa 中 middleware 的思想,利用它我们可以在前端应用中便捷地实现如日志打印、异步请求等功能。
比如在项目中,进行了如下调用后,redux 就集成了 thunk 函数调用以及打印日志的功能。
import thunk from 'redux-thunk' import logger from '../middleware/logger' const enhancer = applyMiddleware(thunk, logger), // 以 redux-thunk、logger 中间件为例介绍中间件的使用 const store = createStore(rootReducer, enhancer)
下面追本溯源,来分析下源码。
applyMiddleware 调用入口
export default function createStore(reducer, preloadedState, enhancer) { // 通过下面代码可以发现,如果 createStore 传入 2 个参数,第二个参数相当于就是 enhancer if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } if (typeof enhancer !== 'undefined') { return enhancer(createStore)(reducer, preloadedState) } ... }
由上述 createStore 源码发现,applyMiddleware 会进行 applyMiddleware(thunk, logger)(createStore)(reducer, preloadedState)
的调用。
export default function applyMiddleware(...middlewares) { return createStore => (...args) => { const store = createStore(...args) let dispatch = store.dispatch let chain = [] const middlewareAPI = { getState: store.getState, // 调用 redux 原生方法,获取状态 dispatch: (...args) => dispatch(...args) // 调用 redux 原生 dispatch 方法 } // 串行 middleware chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch // 返回加工过的 dispatch } } }
可以发现 applyMiddleware 的作用其实就是返回加工过的 dispatch,下面会着重分析 middlewares 是如何串行起来的以及 dispatch 是如何被加工的。
串行 middleware
const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
观察上述代码后发现每个 middleware 都会传入参数 middlewareAPI,来看下中间件 logger 的源码 以及 redux-thunk 的源码, 发现中间件接受的第一个参数正是 ({ dispatch, getState })
// logger 源码 export default ({ dispatch, getState }) => next => action => { console.log(action) return next(action) // 经 compose 源码分析,此处 next 为 Store.dispatch }
// redux-thunk 源码 export default ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch) } return next(action) // 此处 next 为 logger 中间件返回的 (action) => {} 函数 }
dispatch 是如何被加工的
接着上个小节,在 dispatch = compose(...chain)(store.dispatch)
中发现了 compose 函数,来看下 compose 的源码
export default function compose(...funcs) { // ... return funcs.reduce((a, b) => (...args) => a(b(...args))) }
compose 源码中的 funcs.reduce((a, b) => (...args) => a(b(...args)))
算是比较重要的一句,它的作用是返回组合参数后的函数,比如 compose(f, g, h) 等价于 (...args) => f(g(h(...args))),效果图如下所示,调用 this.props.dispatch() 后,会调用相应的中间件,最终会调用 redux 原生的 store.dispatch(),并且可以看到中间件调用的形式类似数据结构中的栈(先进后出)。
拿上个小节提到的 logger、redux-thunk 中间件为例,其 middleware 的内部串行调用方式如下,从而完成了 dispatch 功能的增强(支持如 this.props.dispatch(func)
的调用以及日志功能)。具体可以看 项目中的运用
action => { if (typeof action === 'function') { return action(dispatch) } return (action => { console.log(action) return store.dispatch(action) })(action) }
参考文献
深入React技术栈
作者:牧云云
出处:http://www.cnblogs.com/MuYunyun/"
本文版权归作者和博客园所有,欢迎转载,转载请标明出处。
如果您觉得本篇博文对您有所收获,请点击右下角的 [推荐],谢谢!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
专访方志朋:2018年仍然是微服务飞速发展的一年
方志朋,毕业于武汉理工大学硕士学位。 CSDN博客专家、Spring Cloud中国社区联合创始人。 《深入理解Spring Cloud与微服务构建》作者。Spring Cloud作为Java语言的微服务落地框架,在Spring开源社区和Pivatol、Netflix两大公司的推动下飞速发展,得到了众多开发者的认可,Spring Cloud在未来很可能成为微服务框架的领导者和规范。和众多Spring Cloud开发者一样,方志朋老师在工作和学习中对Spring Cloud系列框架、组件非常痴迷。利用业余时间在CSDN博客上发表了一系列关于Spring Cloud的文章,受到广大开发人员的欢迎,在短短半年的时间里,Spring Cloud系列文章的阅读量就超过200万。 下面跟随小编一起进入方志朋老师的思维世界,同时在文末留言,我们将送出一本《深入理解Spring Cloud与微服务构建》。 1. 异步社区:请您向异步社区的读者做一个简单的介绍吧。 各位读者好,我叫方志朋,毕业于武汉理工大学,是《深入理解Spring Cloud与微服务构建》一书的作者。目前为CSDN博客专家、Sprin...
- 下一篇
MySQL数据库访问性能优化
版权声明:本文为博主原创文章,未经博主允许不得转载。欢迎访问我的博客 https://blog.csdn.net/smooth00/article/details/79399245 MYSQL应该是最流行的WEB后端数据库。大量应用于PHP,Ruby,Python,Java 等Web语言开发项目中,无论NOSQL发展多么快,都不影响大部分架构师选择MYSQL作为数据存储。 MYSQL如此方便和稳定,以至于我们在开发 WEB 程序的时候非常少想到它。即使想到优化也是程序级别的,比方不要写过于消耗资源的SQL语句。可是除此之外,在整个系统上仍然有非常多能够优化的地方。 1优化原理 说起MySQL的查询优化,相信大家会想到:不能使用SELECT *、不使用NULL字段、合理创建索引、为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的工作原理?在实际场景下性能真有提升吗?我想未必。因而理解这些优化建议背后的原理就尤为重要,希望本文能让你重新审视这些优化建议,并在实际业务场景下合理的运用。 MySQL逻辑架构 如果能在头脑中构建一幅MySQL各组件...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7设置SWAP分区,小内存服务器的救世主