2025年3月28日 星期五 甲辰(龙)年 月廿七 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

Redux Middleware 中间件 源码解析

时间:12-14来源:作者:点击数:9
CDSY,CDSY.XYZ

一句话总结,Middleware 就是增强了 dispatch

开始调用 createStore 发生了什么

  • //调用
  • const store = createStore(rootReducer, applyMiddleware(...middlewares));
  • //createStore
  • export default function createStore(reducer, preloadedState, enhancer)
  • //如果第二个参数是function,并且没传第三个参数,则将第二个参数赋值给第三个参数,然后将第二个参数设为undefined
  • if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
  • enhancer = preloadedState
  • preloadedState = undefined
  • }
  • if (typeof enhancer !== 'undefined') {
  • if (typeof enhancer !== 'function') {
  • throw new Error('Expected the enhancer to be a function.')
  • }
  • //返回一个高阶函数
  • return enhancer(createStore)(reducer, preloadedState)
  • }
  • }

通过调用 createStore 返回的结果可以解析为

  • applyMiddleware(...middlewares)(createStore)(reducer, initialState)

applyMiddleware 源码里发生了什么

  • //调用applyMiddleware,可以传入多个中间件
  • export default function applyMiddleware(...middlewares) {
  • return (createStore) => (reducer, initialState, enhancer) => {
  • var store = createStore(reducer, initialState, enhancer)
  • var dispatch = store.dispatch
  • var chain = []
  • //将state和dispatch所指向的函数绑定到middlewareAPI
  • var middlewareAPI = {
  • getState: store.getState,
  • dispatch: (action) => dispatch(action)
  • }
  • //迭代中间件数组,并执行一遍,将middlewareAPI作为最外层的store,并返回一个相当于next函数的数组
  • chain = middlewares.map(middleware => middleware(middlewareAPI))
  • //将数组整理成嵌套的函数体,并将store.dispatch传入最内侧的函数的next,并返回经过处理的dispatch
  • //dispatch是一个函数,是一个嵌套了多层的函数,其最里面调用的是store.dispatch
  • dispatch = compose(...chain)(store.dispatch)
  • //返回一个新的store
  • return {
  • ...store,
  • dispatch
  • }
  • }
  • }

大致看下,其实就是通过一些操作,然后返回一个经过处理的 store、dispatch

具体做了些什么

  • var middlewareAPI = {
  • getState: store.getState,
  • dispatch: (action) => dispatch(action)
  • }
  • chain = middlewares.map(middleware => middleware(middlewareAPI))
  • dispatch = compose(...chain)(store.dispatch)
  1. 定义了一个对象(middlewareAPI),并将 store.state 和 store.dispatch 绑定到这个对象中(都是引用)
  2. 然后循环这些中间件,并将 middlewareAPI 作为参数执行 middleware,因为都是高级函数,所以返回的是 next 数组,并保存到 chain 中
  3. 最重要的是下一步的 compose 函数
  • export default 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)))
  • }

这里有必要解释下 funcs.reduce((a, b) => (...args) => a(b(...args))) 这一坨做了些什么?

reduce 是专门为累加操作设计的,啥意思呢

先把 funcs.reduce((a, b) => (...args) => a(b(...args))) 翻译一下

  1. 假如说 funcs[a,b,c,d,e,f]
  2. 那么执行之后的结果就是 a(b(c(d(e(f(...args)))
  3. 因为是 compose(...chain)(store.dispatch) 调用,所以 ...args 就是 store.dispatch ,原生的 dispatch,就是说最内层,调用的是原生的 dispatch
  4. 这个有个洋葱模型,网上复制一个

所以最后返回的 dispatch 是经过处理的 dispatch:a(b(c(d(e(f(store.dispatch)))


解释下 chain 是什么?

  • //以redux-saga为例
  • //看参数,就知道为什么定义middlewareAPI对象了
  • function sagaMiddleware({ getState, dispatch }) {
  • ...
  • return next => action => {
  • if (sagaMonitor && sagaMonitor.actionDispatched) {
  • sagaMonitor.actionDispatched(action)
  • }
  • const result = next(action) // hit reducers
  • channel.put(action)
  • return result
  • }
  • }
  1. 从源码上可以分析出当执行 chain = middlewares.map(middleware => middleware(middlewareAPI)) 时,直接返回了 next() 函数
  2. 当有一堆 middleware 时,执行 middleware 都返回一个 next() 函数
  3. 所以 chain 就是一个 next() 数组
  4. 而这个 next() 其实就是下一个 middleware
  5. 一直 next 到最里面的执行 store.dispatch

流程

  1. 调用 applyMiddleware 传入 n 个 middleware
  2. 用 middlewareAPI 保存了当前的 store.state,store.dispatch(每个 middleware 共享)
  3. 迭代 middlewares,执行每个 middleware 并携带 middlewareAPI,返回一个 next()
  4. 将 chain 整理成嵌套的函数,最里层调用 store.dispatch
  5. 返回一个经过处理的 dispatch

用一个最恶心的方式总结

  • //模拟三个middleware
  • function A(next){
  • return function A1(action){
  • next(action)
  • }
  • }
  • function B(next){
  • return function B1(action){
  • next(action)
  • }
  • }
  • function C(next){
  • return function C1(action){
  • next(action)
  • }
  • }

假设 dispatch = A(B(C(store.dispatch))) ,开始执行

  • function A1(action){
  • function B1(action){
  • return function C1(action){
  • store.dispatch(action)
  • }
  • }
  • }(action)

一个 action 的执行顺序: A(action) -> B(action) -> C(action) -> store.dispatch(action) ,先从内到外生成新的 func,然后由外向内执行。

CDSY,CDSY.XYZ
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐