koa2 数据api中间件设计模型的实现方法


Posted in Javascript onJuly 13, 2020

假设所有的数据库读取,http api 接口请求都为一个中间件,将中间件当做插件,插入需要获取数据的位置。

api.js

module.exports = async (ctx, next) => {
 ctx.share_data.api_data = await axios.get('/api');

 await next();
};

db.js

module.exports = async (ctx, next) => {
 ctx.share_data.db_data = await mysql_query('SELECT XXX').catch(() => {});

 await next();
};

串联

app.js

const api = require('api.js');
const db = require('db.js');
          
app.get('/get-api', api, (ctx) => ctx.body = ctx.share_data);
app.get('/get-db', db, (ctx) => ctx.body = ctx.share_data);
app.get('/get-api-and-db', api, db, (ctx) => ctx.body = ctx.share_data);

看着挺和谐,但是如果有多个数据中间件串联则会导致接口的响应时间为所有中间件的总和。

并发

可义一个 compose 函数,需要并发的中间件包装起来

super-compose.js

module.exports = (middleware = []) => {
 if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!');
 for (const fn of middleware) {
  if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!');
 }

 return async (context = {}, next = f => f) => {
  await Promise.all(
   middleware.map(middleware => {
    return new Promise((rs, rj) => {
     middleware(context, () => Promise.resolve())
      .then(rs)
      .catch(rj);
    });
   }),
  );

  await next();
 };
};

app.js

const api = require('api.js');
const db = require('db.js');
const superCompose = require('super-compose.js');
          
app.get('/get-api-and-db', superCompose([api, db]), (ctx) => ctx.body = ctx.share_data);

依赖关系

看着貌似解决了,但如何处理具有上下文依赖的情况呢?例如 api_1 依赖 api 的数据。
改下 api.js,加上缓存校验。处理可能被多次compose的重复接口调用

module.exports = async (ctx, next) => {
 if (ctx.share_data.api_data) {
  return await next();
 }

 ctx.share_data.api_data = await axios.get('/api');

 await next();
};

api-1.js

const api = require('api.js');

module.exports = compose([
 api,
 async (ctx, next) => {
  const { api_data: { api_data: { id = 0 } = {} } = {} } = ctx;

  if (id < 0) {
   await next();
  } else {
   ctx.api_data.api_1_data = await axios.get('/api', { params: { id } });
  }

  await next();
 },
])

app.js

const api_1 = require('api_1.js');
const db = require('db.js');
const superCompose = require('super-compose.js');
          
app.get('/get-api-and-db', superCompose([api_1, db]), (ctx) => ctx.body = ctx.share_data);

跳过中间件

有时候,需要根据特定的条件,绕过某些接口调用

改造下 api.js,通过加入过滤列表

module.exports = async (ctx, next) => {
 const { break_list = [] } = ctx;


 if (break_list.includes('api_data')) {
  // 可能会误伤其他组合引用该中间件的情况。
  // 如可能会误伤,可加上。
  // ctx.break_list = break_list.filter(v => v !== 'api_data')
  return await next();
 } else {
  ctx.share_data.api_data = await axios.get('/api');
 }

 await next();
}

app.js

const api = require('api.js');
const db = require('db.js');
const superCompose = require('super-compose.js');
          
app.get(
 '/get-api-and-db',
 async (ctx, next) => {
  ctx.break_list = ['api_data'];
  await next();
 },
 superCompose([api, db]),
 ctx => (ctx.body = ctx.share_data)
);

数据合并处理

结合 super-compose 与 koa-compose 将所有需要的中间件组合起来,在写一个针对页面的controller

const api = require('api.js');
const db = require('db.js');
const superCompose = require('super-compose.js');
const compost = rquire('koa-compose')

const babala = compose([
 superCompose([api, db]),
 async (ctx, next) => {
  const {
   share_data: { api_data: { id = 0 } = {}, db_data: { title } = {} } = {},
  } = ctx;

  ctx.body = { id, title };
  // OR
  // ctx.share_data.babala = {}
 },
]);

app.get(
 '/get-api-and-db',
 babala
);

结尾

解决经常出现的一个函数内大量的接口、逻辑操作,超长的上下文逻辑。

app.get('/api', async ctx => {
 const api_1 = await axios.get('/api_1');
 await api_2 = await axios.get('/api_2');

 // ...
 // ...
 // 这里有一百行
 // ... 
 
 const [api_3, api_4] = await new Promise.all([axios.get('/api_3'), axios.get('/api_4')]);
 
 // ...
 // ...
 // 这里有几百行
 // ...

 ctx.body = {};
});

以上就是koa2 数据api中间件设计模型的实现方法的详细内容,更多关于koa2 中间件设计模型的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
检测input每次的输入是否合法遇到汉字输入就有问题
May 23 Javascript
禁用页面部分JavaScript不是全部而是部分
Sep 03 Javascript
JavaScript实现的双向跨域插件分享
Jan 31 Javascript
javascript中caller和callee详解
Aug 10 Javascript
分享15个大家都熟知的jquery小技巧
Dec 02 Javascript
jquery插入兄弟节点的操作方法
Dec 07 Javascript
jQuery+ajax的资源回收处理机制分析
Jan 07 Javascript
ES6生成器用法实例分析
Apr 10 Javascript
浅谈vue+webpack项目调试方法步骤
Sep 11 Javascript
基于js Canvas实现二次贝塞尔曲线
Dec 25 Javascript
微信小程序bindinput与bindsubmit的区别实例分析
Apr 17 Javascript
vue中使用GraphQL的实例代码
Nov 04 Javascript
浅析JavaScript 函数防抖和节流
Jul 13 #Javascript
详解JavaScript 异步编程
Jul 13 #Javascript
javascript canvas时钟模拟器
Jul 13 #Javascript
微信小程序整个页面的自动适应布局的实现
Jul 12 #Javascript
uniapp 仿微信的右边下拉选择弹出框的实现代码
Jul 12 #Javascript
微信小程序实现列表滚动头部吸顶的示例代码
Jul 12 #Javascript
Js on及addEventListener原理用法区别解析
Jul 11 #Javascript
You might like
dedecms模板标签代码官方参考
2007/03/17 PHP
php中通过数组进行高效随机抽取指定条记录的算法
2013/09/09 PHP
php5.3 goto函数介绍和示例
2014/03/21 PHP
PHP不用递归实现无限分级的例子分享
2014/04/18 PHP
PHP计算日期相差天数实例分析
2016/02/23 PHP
Laravel框架路由和控制器的绑定操作方法
2018/06/12 PHP
推荐10个超棒的jQuery工具提示插件
2011/10/11 Javascript
jquery放大镜效果超漂亮噢
2013/11/15 Javascript
jQuery操作cookie方法实例教程
2014/11/25 Javascript
javascript作用域链(Scope Chain)用法实例解析
2015/11/30 Javascript
简单解析JavaScript中的__proto__属性
2016/05/10 Javascript
Vue.js动态添加、删除选题的实例代码
2016/09/30 Javascript
domReady的实现案例
2016/11/23 Javascript
解决URL地址中的中文乱码问题的办法
2017/02/10 Javascript
详解Node.js中exports和module.exports的区别
2017/04/19 Javascript
vue使用keep-alive实现数据缓存不刷新
2017/10/21 Javascript
实例学习JavaScript读取和写入cookie
2018/01/29 Javascript
[55:42]VG vs VGJ.T 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
pymongo为mongodb数据库添加索引的方法
2015/05/11 Python
python selenium自动上传有赞单号的操作方法
2018/07/05 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
2019/10/16 Python
Python如何使用input函数获取输入
2020/08/06 Python
pycharm2020.2 配置使用的方法详解
2020/09/16 Python
html5移动端价格输入键盘的实现
2019/09/16 HTML / CSS
意大利大型购物中心:Oliviero.it
2017/10/19 全球购物
高中的职业生涯规划书
2013/12/28 职场文书
工地资料员岗位职责
2013/12/31 职场文书
给酒店员工的表扬信
2014/01/11 职场文书
市场营销调查计划书
2014/05/02 职场文书
环境工程专业毕业生求职信
2014/09/30 职场文书
2014年人事部工作总结
2014/12/03 职场文书
先进个人申报材料
2014/12/30 职场文书
英文感谢信范文
2015/01/21 职场文书
实习单位意见
2015/06/04 职场文书
家长会感言
2015/08/01 职场文书
golang连接MySQl使用sqlx库
2022/04/14 Golang