会员登录 - 用户注册 - 设为首页 - 加入收藏 - 网站地图 浅析洋葱模型!
当前位置:首页 >应用开发 >浅析洋葱模型 正文

浅析洋葱模型

时间:2025-11-04 07:18:32 来源:益强数据堂 作者:IT科技 阅读:737次

 

前言

使用过koa的浅析小伙伴们都应该对洋葱模型有所了解,koa的洋葱独特的中间件流程控制就是通过洋葱模型来实现的,那么洋葱模型是模型什么,又是浅析如何实现的呢?

洋葱模型介绍

介绍

上图是洋葱模型比较经典的一个图,通过这个图可以看到,洋葱洋葱模型就像一个洋葱一个,模型是浅析分成多层的,而一个请求进入的洋葱时候,会从外到内依次经过每一层,模型到最内侧之后又从内到外依次经过每一次,浅析而我们就可以在这每一层上面做自己需要做的洋葱操作。

比如一个请求,模型在koa接收到请求的浅析时候,香港云服务器首先需要鉴权,洋葱然后需要对请求参数解析等等,模型完成请求之后,需要处理异常,添加请求头等等操作,而这些操作就可以放到洋葱模型的每一层上面做处理。

示例代码

如下代码为koa的一段示例代码:

const Koa = require(koa); const app = new Koa(); app.use(async (ctx, next) => {   console.log(1);   await next();   console.log(2); }); app.use(async (ctx, next) => {   console.log(3);   await next();   console.log(4); }); app.use(async (ctx, next) => {   console.log(5);   await next();   console.log(6); }); app.listen(8000); 

执行上面的代码,会发现输出的数字顺序为1,3,5,6,4,2,与上面介绍的洋葱模型的执行顺序是一致的。

洋葱模型实现

首先我们先分析一下上面的代码app.use传入了一个异步的函数,而且app.use可以被使用多次,而这些函数在请求进入的时候会依次被调用,这是不是与发布订阅者模式是一致的服务器租用,那首先我们来实现一个app.use

实现一个app.use

export interface Middleware {   (...rest: any): Promise<any>; } export default class Onion {   middlewares: Middleware[] = [];   constructor(middlewares: Middleware[] = []) {     this.middlewares = middlewares;   }   use(middleware: Middleware) {     this.middlewares.push(middleware);   } } 

上面代码我们定义了一个Onion类,通过这个类我们就可以将订阅函数进行收集,如下代码所示

const onion = new Onion() onion.use(async(params, next)=> {    console.log(1)    await next()    console.log(2) }) 

发布者在收集完订阅函数后需要有触发的时机,这时候就需要再给Onion添加一个执行函数

完善Onion

有小伙伴想到发布订阅者的实现代码,可能就会想到这样做:

export default class Onion {   middlewares: Middleware[] = [];   constructor(middlewares: Middleware[] = []) {     this.middlewares = middlewares;   }   use(middleware: Middleware) {     this.middlewares.push(middleware);   }   execute(params: any) {     this.middlewares.forEach(fn => {           fn(params)        })   } } 

但是这样做的话,就无法满足洋葱模型的先入后出的顺序,那我们应该怎么做呢?

1.定义 compose函数

function compose(middlewares: Array<Middleware>) { if (!Array.isArray(middlewares)) {  throw new Error(中间件必须是数组); } for (let i = 0; i < middlewares.length; i++) {  if (typeof middlewares[i] !== function) {    throw new Error(中间件的每一项都必须是函数);  } } return (params: any) => {  let index = 0;  function dispatch(fn: Middleware | undefined) {    if (!fn) {      return Promise.resolve();    }    const next = () => dispatch(middlewares[++index]);    return Promise.resolve(fn(params, next));  }  return dispatch(middlewares[index]); }; } 

2.实现execute

export default class Onion { middlewares: Middleware[] = []; constructor(middlewares: Middleware[] = []) {  this.middlewares = middlewares; } use(middleware: Middleware) {  this.middlewares.push(middleware); } execute(params: any) {  const fn = compose(this.middlewares);  return fn(params); } } 

通过定义componse函数,可以将中间件函数依次按照顺序来执行。

const onion = new Onion(); onion.use(async (params: any, next: Middleware) => {  console.log(1);  await next();  console.log(2); }); onion.use(async (params: any, next: Middleware) => {  console.log(3);  await next();  console.log(4); }); onion.use(async (params: any, next: Middleware) => {  console.log(5);  await next();  console.log(6); }); onion.execute({}); 

这样我们就实现了一个简易版的洋葱模型。

本文转载自微信公众号「前端有的玩」,可以通过以下二维码关注。转载本文请联系前端有的玩公众号。

(责任编辑:IT科技类资讯)

推荐内容
  • 解决电脑开机密码错误问题的有效方法(密码错误怎么办?电脑开机密码错误解决方案来了!)
  • 着色器入门:符号距离函数!
  • SQL Server什么时候启用“锁定内存页”选项 (Windows)
  • MySQL系列之执行SQL 语句时发生了什么?
  • 三星卡刷XP教程(详细步骤教你如何在三星手机上刷入XP系统,享受原汁原味的XP体验)
  • 实时数仓入门训练营:实时计算 Flink 版 SQL 实践