-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
你知道koa中间件执行原理吗? #1
Comments
深入浅出啊,还得多看几遍慢慢消化 |
@shanelau 一起学习交流 |
mark |
虽然完全看不懂,可还是硬着头皮看完了,貌似很流弊的样子…… |
@JeseWang 一点点看,可以看懂得,欢迎一起学习交流哈 |
前面的还好,到后面确实不太行了 😂 就看不太懂了,待我再读一遍 |
@yanyixin 我也花了很多时间才搞清楚😂 |
This was referenced Oct 25, 2017
mark一下,开始学习 |
@daffyfeng 加油😀 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
前言
原文地址
用在前面
用过koa的同学都知道添加中间件的方式是使用koa实例的
use
方法,并传入一个generator函数,这个generator函数可以接受一个next
(这个next到底是啥?这里先不阐明,在后面会仔细说明)。执行use干了嘛
这是koa的构造函数,为了没有其他信息的干扰,我去除了一些暂时用不到的代码,这里我们把目光聚焦在
middleware
这个数组即可。接下来我们要看use方法了
同样去除了一些暂时不用的代码,可以看到每次执行use方法,就把外面传进来的generator函数push到middleware数组中
好啦!你已经知道koa中是预先通过use方法,将请求可能会经过的中间件装在了一个数组中。
接下来我们要开始本文的重点了,当一个请求到来的时候,是怎样经过中间件,怎么跑起来的
首先我们只要知道下面这段
callback
函数就是请求到来的时候执行的回调即可(同样尽量去除了我们不用的代码)这段代码可以分成两个部分
我们分部分来说一下
这段代码对
experimental
做了下判断,如果设置为了true
那么koa中将可以支持传入async函数,否则就执行co.wrap(compose(this.middleware))
。只有一行初始化中间件就做完啦?
我知道koa很屌,但也别这么屌好不好,所以说评价一个好的程序员不是由代码量决定的
我们来看下这段代码到底有什么神奇的地方
把装着中间件
middleware
的数组作为参数传进了compose
这个方法,那么compose做了什么事呢?其实就是把原本毫无关系的一个个中间件给首尾串起来了,于是他们之间就有了千丝万缕的联系。文字解释一下就是,compose将中间件从最后一个开始处理,并一直往前直到第一个中间件。其中非常关键的就是将后一个中间件得到generator对象作为参数(
这个参数就是文章开头说到的next啦,也就是说next其实是一个generator对象
)传给前一个中间件。当然最后一个中间件的参数next
是一个空的generator函数生成的对象。我们自己来写一个简单的例子说明compose是如何将多个generator函数串联起来的
看到了吗?中间件被串起来之后执行的顺序是
gen1 -> gen2 -> gen3 -> noop -> gen3 -> gen2 -> gen1
从而首尾相连,进而发生了关系😈。
co.wrap
所有上述代码可以理解为
好,我们再看看
co.wrap
做了什么,慢慢地一步步靠近了哦可以看到
co.wrap
返回了一个普通函数createPromise
,这个函数就是文章开头的fn
啦。中间件开始跑起来啦
这一段便是请求到来手即将要经过的中间件执行部分,fn执行之后返回的是一个Promise,koa通过注册成功和失败的回调函数来分别处理请求。
让我们回到
createPromise
里面的fn就是经过compose处理中间件后返回的一个generator函数,那么执行之后拿到的就是一个generator对象了,并把这个对象传经经典的co里面啦。如果你需要对co的源码了解欢迎查看昨天写的走一步再走一步,揭开co的神秘面纱,好了,接下来就是看co里面如何处理这个被compose处理过的generator对象了再回顾一下co
我们直接看一下
onFulfilled
,这个时候第一次进co的时候因为已经是generator对象所以会直接执行onFulfilled()
而
gen.next
正是用于去执行中间件的业务逻辑,当遇到yield语句的时候,将紧随其后的结果返回赋值给ret
,通常这里的ret,就是我们文中说道的next
,也就是当前中间件的下一个中间件。拿到下一个中间件后把他交给
next
去处理当中间件执行结束了,就把Promise的状态设置为成功。否则就将
ret
(也就是下一个中间件)再用co包一次。主要看toPromise
的这几行代码即可注意噢
toPromise
这个时候的返回值是一个Promise,这个非常关键,是下一个中间件执行完成之后回溯到上一个中间件中断执行处继续执行的关键看到这里,我们可以总结出,几乎koa的中间件都会被co给包装一次,而每一个中间件又可以通过Promise的then去监测其后一个中间件是否结束,后一个中间件结束后会执行前一个中间件用then监听的操作,这个操作便是执行该中间件yield next后面的那些代码
打个比方:
当koa中接收到一个请求的时候,请求将经过两个中间件,分别是
中间件1
和中间件2
,中间件1
中间件2
那么处理的过程就是co会立即调用onFulfilled来执行中间件1前半部分代码,遇到
yield 中间件2
的时候得到中间件2generator对象,紧接着,又把这个对象放到co里面继续执行一遍,以此类推下去知道最后一个中间件(我们这里的指的是那个空的noop中间件)执行结束,继而马上调用promise的resolve方法表示结束,ok,这个时候中间件2监听到noop执行结束了,马上又去执行了onFulfilled来执行yield noop中间件后半部分代码,好啦这个时候中间件2也执行结束了,也会马上调用promise的resolve方法表示结束,ok,这个时候中间件1监听到中间件2执行结束了,马上又去执行了onFulfilled来执行yield 中间件2后半部分代码,最后中间件全部执行完了,就执行respond.call(ctx);啊 啊 啊好绕,不过慢慢看,仔细想,还是可以想明白的。用代码表示这个过程有点类似
结尾
如果对你理解koa有些许帮助,不介意的话,点击源码地址点颗小星星吧
如果对你理解koa有些许帮助,不介意的话,点击源码地址点颗小星星吧
如果对你理解koa有些许帮助,不介意的话,点击源码地址点颗小星星吧
源码地址
The text was updated successfully, but these errors were encountered: