说说你对koa中洋葱模型的理解?
用过Koa的,肯定对 Middleware(中间件) 有所了解,那我们就用中间件从现象出发,理解洋葱模型
先自定义两个中间件:
logTime:打印时间戳
module.exports=function() {
returnasyncfunction(ctx, next) {
console.log("next前,打印时间戳:", newDate().getTime())
awaitnext()
console.log("next后,打印时间戳:", newDate().getTime())
}
}
logUrl:打印路由
module.exports=function() {
returnasyncfunction(ctx, next) {
console.log("next前,打印url:", ctx.url)
awaitnext()
console.log("next后,打印url:", ctx.url)
}
}
在 index.js 中use:
constKoa=require('koa')
constapp=newKoa()
constlogTime=require('./middleware/logTime')
constlogUrl=require('./middleware/logUrl')
// logTime
app.use(logTime())
// logUrl
app.use(logUrl())
// response
app.use(asyncctx=> {
ctx.body='Hello World'
})
app.listen(3000)
现在启动服务,然后我们随便访问一个路由,比如 /test,会发现这样一个现象:
两个现象:
中间件的执行了两次
执行顺序奇怪,以next函数为分界点:先use的中间件,next前的逻辑先执行,但next后的逻辑反而后执行
第一反应肯定就是:Koa为什么要这么设计?
正常不应该是中间件按顺序从开始到结束执行吗?
确实,如果说使用中间件的场景不存在前后依赖的情况,从头到尾按顺序链式调用完全没问题。但如果存在依赖的情况呢?如果只链式执行一次,怎么能保证前面的中间件能使用之后的中间件所添加的东西呢?
比如上面两个例子,我在 logUrl 的中间件里,对url进行了处理,加上了一个时间戳,然后我想在 logTime 的中间件里拿到这个时间戳并打印
如果只链式执行一次的话,显然无法实现
然后就是顺序的问题,为什么以next为分界线,先use的中间件 next 之后的逻辑反而后执行呢?
还是上面的例子,如果我们在logUrl 中间件里对url加上去的时间戳,是从数据库里取出来的,logTime 中间件肯定得等 logUrl 跑完了才能拿到对应时间戳。所以如果 logTime 之中的next完成的话,肯定是logUrl这个中间件已经跑完了
因此,上述现象1、2的原因就很清晰了
这样我们可以就确定中间件的执行流必定是如下的一个流程:
外层中间件进行前期处理(next 前的逻辑)
调用next,将控制流交给下个中间件,并await其完成,直到后面没有中间件或者没有next函数执行为止
完成后一层层回溯执行各个中间件的后期处理(next 后的逻辑)
这就是洋葱模型
再放出那两张很经典的图:
Koa中,外层中间件称为上游,内层中间件称为下游,现在我们再回头看官网的描述:
先用我们自己的方式理解之后,官方描述就不会太晦涩了
知道了原因,我们肯定得手动来实现一下洋葱模型,加深理解
实现之前肯定得先看一波源码:
koa
koa-compose
来,一步步分析一波:
首先,先看看middleware在源码里是什么数据类型:
然后按流程看,肯定先进app的listen函数:
创建服务的时候,传入了callback函数的返回值,去看看callback函数:
重点就是这里了,我们上面的分析说明想要实现洋葱模型,下面两点缺一不可:
要把上下文ctx对象和下一个中间件next传给当前的中间件
必须要等待下一个中间件执行完,再执行当前中间件的后续逻辑
而这就是compose函数所做的事情,来自于 koa-compose,这里先暂时不贴源码,有一说一很绕,强行看有点难受
所以,我们可以先按自己的思路来试试:
应该不需要解释吧,这样肯定会报错:
因为执行mw2的时候(也就是mw1里的next),并没有把ctx 和 mw3传给它
那么问题来了:我们怎么才能在调用mw1的next时,把ctx 和 mw2给这个next呢?
那我们肯定就需要对middleware数组里的每个元素重新包装一下了,用什么包装呢?
看个例子:
bind会将当时的参数保留下来,这正是我们所需要的,因此,加上一点小小的改动:
这个时候我们再跑一下代码:
这不就实现了吗?刚刚我留了一个坑就是没放 koa-compose 的源码,下面是源码:
红框的部分就是核心代码,大家可以自己看看,如果感觉很绕,可以对比我上面的例子先理解的,贴一下我简化版的代码:
constmiddleware= []
letmw1=asyncfunction (ctx, next) {
console.log("next前,第一个中间件")
awaitnext()
console.log("next后,第一个中间件")
}
letmw2=asyncfunction (ctx, next) {
console.log("next前,第二个中间件")
awaitnext()
console.log("next后,第二个中间件")
}
letmw3=asyncfunction (ctx, next) {
console.log("第三个中间件,没有next了")
}
functionuse(mw) {
middleware.push(mw)
}
use(mw1)
use(mw2)
use(mw3)
letfn=function (ctx) {
returndispatch(0)
functiondispatch(i) {
letcurrentMW=middleware[i]
if(!currentMW) {
return
}
returncurrentMW(ctx, dispatch.bind(null, i+1))
}
}
fn()
OK啦,这样就大工告成了
总结一下吧:一开始通过现象和场景反推,明白了什么时洋葱模型,以及为什么Koa需要使用洋葱模型,最后就是利用源码,简化实现了一下洋葱模型
说说你对koa中洋葱模型的理解?相关推荐
- Koa的洋葱模型到底是什么?
什么是Koa? Koa是一个精简的node框架,被认为是第二代Node框架,其最大的特点就是独特的中间件流程控制,是一个典型的洋葱模型,它的核心工作包括下面两个方面: 将node原生的req和res封 ...
- KOA --- 2. 洋葱模型
一.什么是koa的洋葱模型 特点: 独特的中间件流程控制,就是典型的洋葱模型 二.解析洋葱模型 在两个中间件函数,用 next 隔开 对应的代码Demo const Koa = require('ko ...
- 洋葱模型php,理解Koa洋葱模型
中间件特性 | | | middleware 1 | | | | +-----------------------------------------------------------+ | | | ...
- koa 中间件洋葱模型源码分析
中间件基本使用 app.use(async(ctx,next)=>{ctx.state={username:'jeff'};await next();... })app.use(async(ct ...
- 聊一聊KOA的洋葱模型
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小.更富有表现力.更健壮的基石. 通过利用 async 函数,Koa ...
- Koa核心—洋葱模型
洋葱模型 koa框架的业务流程是一个完全的异步编程模型,通过ctx上下文对象来贯穿http的上下游.那么我们最重要的就是理解洋葱模型. const koa = require("Koa&qu ...
- 洋葱模型php,聊一聊KOA的洋葱模型
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小.更富有表现力.更健壮的基石. 通过利用 async 函数,Koa ...
- KOA 初探 洋葱模型
KOA 官网链接 当然,如果你有express的基础就最好了,毕竟是原班人马开发 常用的指令 npm install koa npm install nodemon touch app.js node ...
- CSS中盒模型的理解
1.基本的盒模型知识 CSS css盒子模型 又称框模型 (Box Model) ,包含了元素内容(content).内边距(padding).边框(border).外边距(margin)几个要素.如 ...
最新文章
- 【BZOJ-3712】Fiolki LCA + 倍增 (idea题)
- 姚班天才漆子超、IOI金牌得主陈启峰等联手进军AR领域:全员顶尖科技公司技术背景,打造“5G+AI+AR”先锋...
- Python网络编程:IO多路复用
- 英语关于计算机的作文600字,有关电脑的作文600字
- win7 IIS7.5 HTTP 错误 404.17 - Not Found 请求的内容似乎是脚本,因而将无法由静态...
- Python CSV 中查找指定字符串
- 一个 Task 不够,又来一个 ValueTask ,真的学懵了!
- 深度学习去燥学习编码_我们问了15,000个人,他们是谁,以及他们如何学习编码
- redis学习笔记-安装与入门
- IE浏览器开发人员工具怎么使用
- 转:libev和libevent的设计差异
- Hibernate中常见问题 No row with the given identifier exists问题
- 有linux服务器用来干什么用的,linux集群能干什么
- 1012 数字分类 (20 分)—PAT (Basic Level) Practice (中文)
- nagios监控php使用情况,给nagios增加监控当前php进程数的插件,并用pnp出图
- Windows,bat批量ping脚本
- hdu 1427 24点暴力dfs
- 能上QQ但是打不开网页
- 如何提高英文的科研写作能力——施一公
- python爬虫|post的响应,利用python实现有道翻译在线翻译
热门文章
- 【C++错误】VS调试出现0xC00000FD:Stack overflow溢出
- java ueditor 图片上传加水印_百度ueditor上传图片加水印的例子
- 程序员CMD命令大全
- 达人深度评测vivos7e和OPPOK7x参数对比 vivos7e和OPPOK7x哪个好
- 33岁的外行妈妈,转行金融业可行吗?(此贴仅限于个人感悟)
- Java实现台阶问题
- 折叠屏已经不新鲜了,明天你可能会用上“伸缩屏幕”!
- 与一汽密谈 南汽罗孚点将起航
- 离线安装clamav
- CentOs解决下载速度慢 更换下载源