找回密码
 立即注册
首页 业界区 业界 详解中间件

详解中间件

齐娅晶 2025-6-2 23:43:01
中间件(Middleware)是软件开发中一种常见的设计模式,其核心思想是‌在核心逻辑的执行过程中插入可扩展的附加功能模块‌。以下是中间件的核心概念和特点:
‌一、中间件的本质

中间件本质上是 ‌"业务逻辑的增强层"‌,它像流水线上的加工环节,对输入的数据或事件进行预处理、拦截或后处理,但不改变核心逻辑本身。
‌二、典型特征‌

1、链式调用(洋葱模型)
多个中间件形成处理链,依次传递处理权,可以同时处理请求(Request)和响应(Response),类似流水线作业。
2、可插拔性
中间件可按需组合,灵活添加或移除功能模块,无需修改核心代码。
3、职责单一原则
每个中间件专注一个独立功能(如日志记录、权限验证等)。
‌三、核心工作原理

假设一个包含三个中间件的处理流程(伪代码):
  1. // 中间件链式调用逻辑
  2. const middlewareChain = [
  3.   (next) => (input) => {
  4.     console.log("Middleware 1开始");
  5.     next(input); // 传递到下一个中间件
  6.     console.log("Middleware 1结束");
  7.   },
  8.   (next) => (input) => {
  9.     console.log("Middleware 2开始");
  10.     next(input);
  11.     console.log("Middleware 2结束");
  12.   },
  13.   (next) => (input) => {
  14.     console.log("核心逻辑执行");
  15.     return "处理结果";
  16.   }
  17. ];
  18. // 输出结果:
  19. // Middleware 1开始
  20. // Middleware 2开始
  21. // 核心逻辑执行
  22. // Middleware 2结束
  23. // Middleware 1结束
复制代码
下面是一个手写redux的例子
createStore:
  1. /**
  2. * 判断是否是平面对象
  3. * @param {*} obj
  4. */
  5. function isPlainObject(obj){
  6.     if(typeof obj!='object'){
  7.         return false;
  8.     }
  9.     return Object.getPrototypeOf(obj) === Object.prototype
  10. }
  11. /**
  12. * 生成一个6位的随机字符串
  13. */
  14. function getRandomStr(len){
  15.     return Math.random().toString(36).substring(2,len+2).split("").join(".");
  16. }
  17. export default function(reducer,initState){
  18.     let currentReducer = reducer,currentState = initState;
  19.     let listens = [];
  20.     function dispatch(action){
  21.         //限制条件
  22.         //action 必须是一个平面对象
  23.         //必须有type属性
  24.         if(!isPlainObject(action)){
  25.             throw new TypeError('action必须是平面对象');
  26.         }
  27.         if(action.type === undefined){
  28.             throw new TypeError('action对象必须有type属性');
  29.         }
  30.         currentState = currentReducer(currentState,action);
  31.         //store更新完state之后 依次调用添加的监听器
  32.         for (const listen of listens) {
  33.             listen();
  34.         }
  35.     }
  36.     //初始化store的时候会默认 dispatch一个特殊的type类型
  37.     dispatch({
  38.         type:`@@redux/INIT${getRandomStr(6)}`
  39.     })
  40.     function getState(){
  41.         return currentState;
  42.     }
  43.     function subscribe(listen){
  44.         listens.push(listen);
  45.         //如果已经取消监听了 则直接返回
  46.         let isRemove = false;
  47.         //返回一个函数 执行清除监听器的操作
  48.         return function(){
  49.             if(isRemove){
  50.                 return;
  51.             }
  52.             const index = listens.indexOf(listen);
  53.             listens.splice(index,1);
  54.             isRemove = true;
  55.         }
  56.     }
  57.     return {
  58.         dispatch,
  59.         getState,
  60.         subscribe
  61.     }
  62. }
复制代码
bindActionCreators:
  1. /**
  2. * //bindActionCreators 直接接收一个action创建函数 和 store.dispatch 如果是一个函数则直接调用 内部去dispatch action
  3. //如果接收的是一个对象 返回的跟对象属性相同的数据结构  内部去dispatch action
  4. */
  5. export default function(obj,dispatch){
  6.     if(typeof obj === "function"){
  7.         return getAutoDispatchAction(obj,dispatch)
  8.     }else if(typeof obj === "object"){
  9.         let result = {};
  10.         for (const key in obj) {
  11.             if (Object.prototype.hasOwnProperty.call(obj, key)) {
  12.                 const actionCreater = obj[key];
  13.                 result[key] = getAutoDispatchAction(actionCreater,dispatch);
  14.             }
  15.         }
  16.         return result;
  17.     }else{
  18.         throw new TypeError("报错了");
  19.     }
  20. }
  21. function getAutoDispatchAction(actionCreate,dispatch){
  22.     /**
  23.      * 将参数汇总成数组  (arg1,arg2)  变成[arg1,arg2]
  24.      * 函数内部展开是重新变成(arg1,arg2) (展开运算符)
  25.      */
  26.     return function(...args){
  27.         const action = actionCreate(...args);
  28.         dispatch(action);
  29.     }
  30. }
复制代码
applyMiddleware:
  1. import compose from "./compose";
  2. /**
  3. * 外层函数捕捉中间件集合
  4. * 中层函数接收创建原始厂库的函数
  5. * 内层函数 用来增强原始厂库 增强原始的dispatch函数
  6. */
  7. export default function(...middlewares){
  8.     return function(createStore){
  9.         return function(reducer,defaultState){
  10.             const store = createStore(reducer,defaultState);
  11.             let dispatch = (...args)=>{
  12.                 throw new Error("Dispatching while constructing your middleware is not allowed. ");
  13.             };
  14.             const simpleStore = {
  15.                 getState:store.getState,
  16.                 dispatch:(...arge) => dispatch(...arge)
  17.             }
  18.             //返回的是创建dispatch函数的集合  每一个元素都是一个函数  调用函数会返回dispatch函数
  19.             const dispatchProducers = middlewares.map((mid)=>mid(simpleStore));
  20.             console.log(dispatchProducers)
  21.             dispatch = compose(...dispatchProducers)(store.dispatch)
  22.             return {
  23.                 ...store,
  24.                 dispatch
  25.             }
  26.         }
  27.     }
  28. }
复制代码
compose:
  1. export default function(...middlewares){
  2.     return middlewares.reduce((a,b)=>(...args)=>a(b(...args)))
  3.     // return function(...args){
  4.     //     let lastReturn = null;
  5.     //     for (let index = middlewares.length-1; index >=0; index--) {
  6.     //         //最后一个 将默认的dispatch传递给最后一个中间件  该中间件调用返回一个新的dispatch  并将这个新的dispatch作为参数传递给下一个中间件
  7.     //         if(index == middlewares.length-1){
  8.     //             //该函数接收一个dispatch函数 并返回一个新的dispatch函数
  9.     //             lastReturn = middlewares[index](...args)
  10.     //         }else{
  11.     //             lastReturn = middlewares[index](lastReturn);
  12.     //         }
  13.     //         lastReturn.displayName = `applayMiddle-${index}`;
  14.     //     }
  15.     //     return lastReturn;
  16.     // }
  17. }
复制代码
中间件的组合逻辑:
其核心原理确实与闭包密切相关。具体执行流程如下:

  • ‌中间件链式调用机制‌:


  • 代码通过倒序循环(从最后一个中间件开始)构建调用链
  • 每个中间件接收前一个中间件返回的函数作为参数(即next参数)
  • 最终返回的是包装了所有中间件逻辑的新dispatch函数

  • ‌闭包的关键作用‌:


  • 每个中间件函数都通过闭包保存了对前一个中间件返回函数的引用
  • 当调用最终返回的dispatch时,会触发第一个中间件的执行,其内部的next()会调用闭包保存的下一个中间件
  • 这种链式调用会一直传递到原始dispatch(即代码中的...args)
这种设计模式被称为"洋葱模型",请求从外层中间件进入,响应从内层中间件返回。闭包机制确保了每个中间件都能访问到正确的next函数引用,从而形成完整的调用链。
最后统一导出:
  1. export {default as createStore} from './createStore';
  2. export {default as bindActionCreators} from './bindActionCreators';
  3. export {default as combineReducers} from './combineReducers';
  4. export {default as applyMiddleware} from './applyMiddleware';
复制代码
 
 
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册