Koa 源码解析
最近有用到 Express 以及 Koa 做一些 Mock Server 以及开发平台的搭建工作,这篇文章会把 Koa 常用方法的流程源码梳理一下,用到的 Koa 版本是 2.7.0 。
文件结构
在项目依赖了 Koa 后,可以从 node_modules 中找到 koa 文件夹,文件结构大概如下:
koa-files可以看到其相关源文件只有四个, application 应用, context 上下文, request 以及 response 的封装。
Koa 实例创建, 监听端口及回调函数
koa-start如图所示这里我们创建了一个 Koa 实例,然后简单的返回了内容并开始监听 6060 端口,下面则是 Koa 实例的 constructor
代码:
一些初始化工作:
~ 初始化中间件数组
~ 读取环境参数
~ 初始化 context, request, response 对象
另外我们可以看到 Koa Application 继承自 Node.js 的 Emitter 类,来继承事件触发以及事件监听的能力。
koa-listenlisten
方法则只是对 http 模块方法的调用,只不过把回调函数 handle 到自己这里。
use
方法先是类型检查,也附带对函数是不是 Generator Function 进行了检查,Koa v3 后则不再支持 generators ,取而代之推荐使用 async/await
。 之后则是直接把传入的函数 push 进中间件数组,支持链式调用,返回 this 。
再来看看作为回调处理传给 http 创建时候的 callback 方法
compose 函数把所有 middleware 结合到一起, 然后创建一个函数常量,内部会创建一个上下文对象提供给每个 middleware 获取 request, response 以及其他信息。
下面会详细介绍 middleware 处理流程以及 context 对象。
Middleware
Koa 是一个相对轻量级的库,这个 compose 方法在一个 koa-compose 的包中,这个包也只有这一个方法的实现:
koa-compose上来是参数对象以及数组中的对象类型校验,然后 call 了内部方法 dispatch ,每一个 fn 调用时都通过 Promise 来支持异步,从第一个索引一直调用到最后,因为每一个中间件都能获取到 context 以及 next 函数,所以在最后 resovle 中是调用 fn(context, dispatch.bind(null, i+1))
另外因为中间件拥有足够的自由度来决定什么时候执行 next 函数,所以 middleware 执行中间件的流程大概如图所示
koa-middlewareContext
上面提到过,在回调方法内会先创建一个上下文对象:
koa-create-context这个方法比较简单,大部分为赋值操作,为了让使用者能够从 context, request 以及 response 对象上获取到更多的信息。
然后进到 context.js 里看下 context 的结构:
koa-context里面有一些工具方法,error 处理以及 cookies 的 getter, setter, 最后面是通过代理能够访问到 request 以及 response 的属性,方法等。
Request & Response
从上面的 createContext 方法可以看到, request 以及 response 都是基于 http lib 的 request 以及 response 进行的封装和扩展,具体的属性以及方法解释可以看 Koa 官方的文档:
关于 Koa 和 Express
最后针对 Koa 和 Express 进行一些比较,可以看下 Koa 官方的介绍:
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。
它们属同一团队开发, Koa 更轻量级不会像 Express 一样内置很多中间件,从性能上讲 Koa 会更好一些,从场景上看, 比如我实现一个 Mock Server, Express 反而更容易一些,因为不需要去手动引用和管理依赖。