# ioioi **Repository Path**: daoio/ioioi ## Basic Information - **Project Name**: ioioi - **Description**: 洋葱模型执行引擎,只是最核心的实现,基于此可以实现前后端的应用。 - **Primary Language**: JavaScript - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-08-10 - **Last Updated**: 2024-02-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## ioioi:洋葱模型执行引擎 ioioi仅仅提供一个洋葱模型的执行机制。无论是前端还是后端(Node.js)都可以基于此开发自己的应用。 其核心机制只有不到80行代码。ioioi利用 async 和 await 实现,现在的前后端都是完美支持的,请尽情使用。但是如果你要用在古老的项目上,请慎重!! ### 安装 ``` npm i ioioi ``` ### 详细说明 这不是一个开箱即用的工具,而是一个给需要造轮子的开发者使用的组件。一般来说,在开发中会经常需要分层处理以及通过组件灵活组合的情况,无论是操作系统还是web应用。 在众多的编程语言和开发框架以及各种成型的系统上,中间件、拦截器、钩子等名词经常会出现,它们本质上没有什么区别,为了让程序易于扩展、方便维护和定制。而且实现了组件或是模块的分离,还方便大家协作。 这个扩展主要还是专注于web领域,可以用于前端,也可以用在后端,因为其简单,没有涉及到任何前后端专有的东西。 ### 使用 ``` JavaScript const ioioi = require('ioioi'); const ioi = new ioioi(); ioi.use(async (c, next) => { console.log('m1 in'); await next(); console.log('m1 out'); }); ioi.use(async (c, next) => { console.log('m2 in'); await next(); console.log('m2 out'); }); //run是async声明的函数,你可以用在try catch中捕获错误 ioi.run(); ``` 执行结果: ``` m1 in m2 in m2 end m1 end ``` 执行结果是按照洋葱模型的,只是遵循的是先添加先执行的原则,因为这样更符合编码逻辑。 在之前的示例上,没有对run传递参数,实际上,run是接收一个对象作为参数的。在web请求中,总是被称为请求上下文。不过在这里,你可以按照自己的设计执行。 **run是async声明的函数,你可以用在try catch中捕获错误。** ### 传递参数 ``` JavaScript const ioioi = require('ioioi'); function context() { return { method : '', url : '', path : '', exec : null }; } const ioi = new ioioi(); ioi.use(async (c, next) => { console.log('m1 in'); await next(); console.log('m1 out'); }); ioi.use(async (c, next) => { console.log('m2 in'); await next(); console.log('m2 out'); }); //添加第三个中间件输出传递上下文对象的信息。 ioi.use(async (c, next) => { console.log(c.method, c.url); await next(); }); let ctx = context(); ctx.method = 'GET'; ctx.path = '/'; ctx.url = '/?name=home'; //如果传递参数对象存在属性exec并且是可执行函数,则会执行。 //并且把ctx自身作为参数传递。 ctx.exec = async (c) => { console.log('我是最核心的应用,没有next。'); }; ioi.run(ctx); ``` 输出结果: ``` m1 in m2 in GET /?name=home 我是最核心的应用,没有next。 m2 out m1 out ``` 如果传递参数对象存在属性exec并且是可执行函数,则会执行,并且会把ctx自身作为参数传递,你不必使用this来获取ctx。避免this指向错误带来的问题。 ### 过滤执行 use原型如下: ``` use (midcall, filter = null) { //... } ``` 使用use添加中间件,还支持第二个参数,默认为null。如果要起作用,则需要传递一个函数对象,其主要作用是对执行过程过滤,执行时,会把中间件接收到的参数传递过去,注意只有第一个参数传递,没有next。如果函数返回false则表示不通过,不会执行此中间件。 ``` JavaScript const ioioi = require('ioioi'); function context() { return { exec : null, method : '', pass : '' }; } let ioi = new ioioi(); let postCheck = (c) => { if (c.method == 'POST' && c.pass !== 'abc') { console.log(' post deny'); return false; } return true; }; ioi.use(async (c, next) => { console.log('m1 in'); await next(); console.log('m1 out'); }); ioi.use(async (c, next) => { console.log(' m2 in'); await next(); console.log(' m2 out'); }, postCheck); ioi.use(async (c, next) => { console.log(' m3 in'); await next(); console.log(' m3 out'); }); let b = context(); b.method = 'POST'; b.pass = 'abcd'; b.exec = async (c) => { console.log(' I am b'); }; ioi.run(b); ``` 执行结果: ``` m1 in post deny m3 in I am b m3 out m1 out ``` 可以看到,中间件m2的输出没有执行,因为POST检测没有通过,函数返回false。如果你把pass改成abc,让postCheck检测通过,则会看到如下输出: ``` m1 in m2 in m3 in I am b m3 out m2 out m1 out ``` ## 最后 简洁却极富表现力的功能,授之以渔。