koa context
在分析koa
其他原理之前,首相需要理解koa
中提出的context
到底是什么,下面用一张图来说明

抽象和封装
抽象出
Request
,Response
,Context
三大类,封装常用操作将
Request
,Response
,部分方法代理到Context
上为了实现最终用一个`Context`实例携带全部属性方法,传递给中间件使用
实例化
Request
,Response
,Context
,并将其实例关联Koa Application
实例(示例图中的app
),Node.js
的http request
实例(示例图中的req
),Node.js
的http response
实例(示例图中的res
)关联起来关联的部分原因是`Request`, `Response`, `Context`封装常用操作时,用到了`app`,`req`,`res` 另一部分原因是保留原始`req`,`res`数据
这样一来,Context
的实例就将一个http server
常用的全部属性方法全部封装到一个上下文中,方便传递给中间件调用,完成了请求准备工作
koa middleware
启动过程分析
1 | listen() { |
从上面可以看出,callback
函数完成了所有的请求处理工作,这里是callback
源码1
2
3
4
5
6
7
8
9
10
11
12callback() {
const fn = compose(this.middleware);
if (!this.listeners('error').length) this.on('error', this.onerror);
return (req, res) => {
res.statusCode = 404;
const ctx = this.createContext(req, res);
onFinished(res, ctx.onerror);
fn(ctx).then(() => respond(ctx)).catch(ctx.onerror);
};
}
启动的过程:
compose
中间件- 生成
Node.js
原生请求处理函数创建上下文实例ctx(也就是生成`koa context`实例) 执行中间件函数
创建上下文中间件,也就是生成Context
实例对象,上文已经详细描述过
执行中间件函数,这行代码就是执行compose
中间件之后返回的Pormise
对象,所以我们把重点放在compose
的过程上
compose中间件
const fn = compose(this.middleware);
简单来说,这行代码的作用就是将所有的中间件有序组合,成为一个Promise
对象返回,compose
函数来自koa-compose
。这里是源码
1 |
|
首先看返回值,返回的是一个中间件函数
function (context, next)
,我们从前面koa callback
函数的这行代码中可以观察到,(fn就是compose返回的中间件函数)一次fn的调用就结束了整个请求,所以fn最终的作用就是依次调用所有的中间件1
fn(ctx).then(() => respond(ctx)).catch(ctx.onerror);
然后是dispatch函数,这个函数的返回值是一个
Promise
对象(Promise.resolve
和Promise.reject
是将一个现有对象转化为一个promise对象,状态不同),这个Promise
对象是由原始的中间件函数构造而成的。原始的中间件函数就是传递给`app.use()`的函数
将上下文
context
和next
函数传递给原始中间件对象,context
就是中间件函数的context
,这里的next
函数是递归的关键,next
函数返回dispatch
函数执行结果,也就是下一个被包装成Promise
对象的中间件函数,这也就是为什么我们在koa2
中执行完一个中间件,如果还需要执行下一个中间件的时候,需要执行await next()
的原因
中间件回逆特性
先来看一张图

从上面的分析我们已经知道,
await next()
相当于在执行下一个中间件,那么在await next()
之后我们执行的操作又是什么呢?这个就是koa
中间件回逆的特性,在下一个中间件执行完成之后,在http请求响应完成之前,你还可以做一些非常有用的操作,这整个过程,称之为回逆。这是个非常有用的特性,举个非常简单的例子,用下面这段代码可以非常简单的统计出中间件处理请求的时间
1 | app.use(async function (ctx, next) { |
总结
从koa2源码分析我们可以看出,koa最重要的两个知识点就是context
和middleware
,再实际使用过程中,深度感受这两点,一定能有更多的收获
补充
其实async
函数就是generator
函数的语法糖,要再深入的理解中间件的compose原理和回逆原理,还是需要koa@master源码的中去理解