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 代码:

koa-constructor

一些初始化工作:
~ 初始化中间件数组
~ 读取环境参数
~ 初始化 context, request, response 对象

另外我们可以看到 Koa Application 继承自 Node.js 的 Emitter 类,来继承事件触发以及事件监听的能力。

koa-listen

listen 方法则只是对 http 模块方法的调用,只不过把回调函数 handle 到自己这里。

koa-use

use 方法先是类型检查,也附带对函数是不是 Generator Function 进行了检查,Koa v3 后则不再支持 generators ,取而代之推荐使用 async/await 。 之后则是直接把传入的函数 push 进中间件数组,支持链式调用,返回 this 。

koa-callback

再来看看作为回调处理传给 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-middleware

Context

上面提到过,在回调方法内会先创建一个上下文对象:

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 反而更容易一些,因为不需要去手动引用和管理依赖。

-- EOF --
以上为本篇博客的全部内容,欢迎提出建议和指正,
个人联系方式详见关于

Comments
Write a Comment