You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function compose(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 function(context, next) {
// last called middleware #
let index = -1
return dispatch(0)
function dispatch(i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
// 当前执行第 i 个中间件
index = i
let fn = middleware[i]
// 所有的中间件执行完毕
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
// 执行当前的中间件
// 这里的fn也就是app.use(fn)中的fn
return Promise.resolve(fn(context, function next() {
return dispatch(i + 1)
}))
} catch (err) {
return Promise.reject(err)
}
}
}
}
Koa vs Express
Koa是继Express之后,Node的又一主流Web开发框架。相比于Express,Koa只保留了核心的中间件处理逻辑,去掉了路由,模板,以及其他一些功能。详细的比较可以参考Koa vs Express。
另一方面,在中间件的处理过程中,Koa和Express也有着一定区别,看下面例子:
Node自带的http模块处理请求的时候,参数是一个req和res,分别为http.IncomingMessage和http.ServerResponse的实例。
Express对请求参数req和res的原型链进行了扩展,增强了req和res的行为。
而Koa并没有改变req和res,而是通过req和res封装了一个ctx (context)对象,进行后面的逻辑处理。
Koa基本组成
Koa源码非常精简,只有四个文件:
Application
Application主要维护了中间件以及其它一些环境:
首先会通过this.callback方法来返回一个函数作为http.createServer的回调函数,然后进行监听。我们已经知道,http.createServer的回调函数接收两个参数:req和res,下面来看this.callback的实现:
首先是将所有的中间件通过 compose 组合成一个函数fn,然后返回http.createServer所需要的回调函数。于是我们可以看到,当服务器收到一个请求的时候,会使用req和res通过this.createContext方法来创建一个上下文环境ctx,然后使用fn来进行中间件的逻辑处理。
Context
通过上面的分析,我们已经可以大概得知Koa处理请求的过程:当请求到来的时候,会通过req和res来创建一个context (ctx),然后执行中间件。
事实上,在创建context的时候,还会同时创建request和response,通过下图可以比较直观地看到所有这些对象之间的关系。
context
图中:
实际上,ctx主要的功能是代理request和response的功能,提供了对request和response对象的便捷访问能力。在源码中,我们可以看到:
这里使用了 delegates 模块来实现属性访问的代理。简单来说,通过delegate(proto, 'response'),当访问proto的代理属性的时候,实际上是在访问proto.response的对应属性。
Request & Response
Request对req进行了抽象和封装,其中对于请求的url相关的处理如图:
┌────────────────────────────────────────────────────────┐
│ href │
├────────────────────────────┬───────────────────────────┤
│ origin │ url / originalurl │
├──────────┬─────────────────┼──────────┬────────────────┤
│ protocol │ host │ path │ search │
├──────────├──────────┬──────┼──────────┼─┬──────────────┤
│ │ hostname │ port │ │?│ querystring │
│ ├──────────┼──────┤ ├─┼──────────────┤
│ │ │ │ │ │ │
" http: │ host.com : 8080 /p/a/t/h ? query=string │
│ │ │ │ │ │ │
└──────────┴──────────┴──────┴──────────┴─┴──────────────┘
Response对res进行了封装和抽象,这里不做赘述。
中间件的执行
在上面已经提到,所有的中间件会经过 compose 处理,返回一个新的函数。该模块源码如下:
Koa的中间件支持普通函数,返回一个Promise的函数,以及async函数。由于generator函数中间件在新的版本中将不再支持,因此不建议使用。
参考资料:
koa2-note
koa-guide
koa-0.0.2
带你走进koa2的世界(koa2源码浅谈)
深入浅出 Koa
Koa2源码初读
The text was updated successfully, but these errors were encountered: