浅析洋葱模型

 [[407985]]

前言

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

专注于为中小企业提供成都网站设计、成都网站建设服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业赣榆免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了上千企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。

洋葱模型介绍

介绍

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

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

示例代码

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

 
 
 
 
  1. const Koa = require('koa'); 
  2. const app = new Koa(); 
  3.  
  4. app.use(async (ctx, next) => { 
  5.   console.log(1); 
  6.   await next(); 
  7.   console.log(2); 
  8. }); 
  9.  
  10. app.use(async (ctx, next) => { 
  11.   console.log(3); 
  12.   await next(); 
  13.   console.log(4); 
  14. }); 
  15. app.use(async (ctx, next) => { 
  16.   console.log(5); 
  17.   await next(); 
  18.   console.log(6); 
  19. }); 
  20.  
  21. app.listen(8000); 

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

洋葱模型实现

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

实现一个app.use

 
 
 
 
  1. export interface Middleware { 
  2.   (...rest: any): Promise
  3.  
  4. export default class Onion { 
  5.   middlewares: Middleware[] = []; 
  6.   constructor(middlewares: Middleware[] = []) { 
  7.     this.middlewares = middlewares; 
  8.   } 
  9.  
  10.   use(middleware: Middleware) { 
  11.     this.middlewares.push(middleware); 
  12.   } 

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

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

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

完善Onion

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

 
 
 
 
  1. export default class Onion { 
  2.   middlewares: Middleware[] = []; 
  3.   constructor(middlewares: Middleware[] = []) { 
  4.     this.middlewares = middlewares; 
  5.   } 
  6.  
  7.   use(middleware: Middleware) { 
  8.     this.middlewares.push(middleware); 
  9.   } 
  10.  
  11.   execute(params: any) { 
  12.     this.middlewares.forEach(fn => { 
  13.           fn(params) 
  14.        }) 
  15.   } 

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

1.定义 compose函数

 
 
 
 
  1. function compose(middlewares: Array) { 
  2. if (!Array.isArray(middlewares)) { 
  3.  throw new Error('中间件必须是数组'); 
  4. for (let i = 0; i < middlewares.length; i++) { 
  5.  if (typeof middlewares[i] !== 'function') { 
  6.    throw new Error('中间件的每一项都必须是函数'); 
  7.  } 
  8.  
  9. return (params: any) => { 
  10.  let index = 0; 
  11.  function dispatch(fn: Middleware | undefined) { 
  12.    if (!fn) { 
  13.      return Promise.resolve(); 
  14.    } 
  15.    const next = () => dispatch(middlewares[++index]); 
  16.    return Promise.resolve(fn(params, next)); 
  17.  } 
  18.  return dispatch(middlewares[index]); 
  19. }; 

2.实现execute

 
 
 
 
  1. export default class Onion { 
  2. middlewares: Middleware[] = []; 
  3. constructor(middlewares: Middleware[] = []) { 
  4.  this.middlewares = middlewares; 
  5.  
  6. use(middleware: Middleware) { 
  7.  this.middlewares.push(middleware); 
  8.  
  9. execute(params: any) { 
  10.  const fn = compose(this.middlewares); 
  11.  return fn(params); 

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

 
 
 
 
  1. const onion = new Onion(); 
  2. onion.use(async (params: any, next: Middleware) => { 
  3.  console.log(1); 
  4.  await next(); 
  5.  console.log(2); 
  6. }); 
  7.  
  8. onion.use(async (params: any, next: Middleware) => { 
  9.  console.log(3); 
  10.  await next(); 
  11.  console.log(4); 
  12. }); 
  13.  
  14. onion.use(async (params: any, next: Middleware) => { 
  15.  console.log(5); 
  16.  await next(); 
  17.  console.log(6); 
  18. }); 
  19.  
  20. onion.execute({}); 

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

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

分享文章:浅析洋葱模型
转载注明:http://www.csdahua.cn/qtweb/news40/67690.html

网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网