Koa 解析( 三 )

在这里主要是明确 context 挂载的内容 , 这个 context 是 每一次请求都会生成 的 。 由代码可知:

  1. 每个应用实例 app 都会有对应的 context 、 request 、 response 实例(即 this.xxx ) 。 每个请求 , 都会基于这些实例来创建自己的实例 。 这样做的目的是为了不污染全局的变量 。
  2. 将 node 原生的 req 、 res 以及 this 挂载到 context 、 request 、 response 上 。
  3. 将创建的 context 返回 , 传入所有中间件的第一个参数 , 作为这个请求的上下文 。
着重解释一下第 2 点 , 为什么要把这些属性挂载上去 。 除了便利性外 , 我们通过查看源码 resquest.js response.js 文件还可以知道:所有的这些访问都是代理 , 最终访问的还是 node 原生的 req 、 res。
koa-compose 实现洋葱圈模型接下来 , 我们来看看源代码中的 koa-compose 插件是如何实现洋葱圈模型:
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) {// 上一次被执行的中间件let index = -1return dispatch(0)function dispatch (i /*表示预期想要执行哪个中间件*/) {if (i <= index) return Promise.reject(new Error('next() called multiple times'))index = ilet fn = middleware[i]if (i === middleware.length) fn = next// 没有fn的话 , 直接返回一个已经reolved的Promise对象if (!fn) return Promise.resolve()try {/*原代码是一行 , 为了方便理解拆成了三行const next = dispatch.bind(null, i + 1);const fnResult = fn(context, next);return Promise.resolve(fnResult);*/return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));} catch (err) {return Promise.reject(err)}}}}简单来看 , 在 compose 中会根据变量 i 挨个执行中间件 , 以递归的方式来执行 。整个过程不难理解 , 实现较为巧妙 。值得注意的是:每一次 dispatch() 的返回值都是 Promise。 可参考下面的动图来过一遍上面代码的实现 。
Koa 解析文章插图
解析 handleRequest我们来看看 , 得到了每个请求的上下文信息 context 与 经过 compose 后的中间件逻辑之后 , 我们来看看最终如何处理请求的:
handleRequest(ctx, fnMiddleware) {const res = ctx.res;res.statusCode = 404;const onerror = err => ctx.onerror(err);const handleResponse = () => respond(ctx);onFinished(res, onerror);// 执行 compose 后的中间件函数 , 最后执行 respondreturn fnMiddleware(ctx).then(handleResponse).catch(onerror);}执行 compose 后的中间件函数 , 最后执行 respond 方法 。 经查看 , 可以知道 , 主要是对响应进行封装 , 并且赋值给到 context.res.end(body)。
总结综上 , 我们简单地对 Koa 进行了介绍;同时通过解析 Demo 文件的执行过程 , 我们从源码级别窥见了 Koa 的一些相关原理实现 。 至此 , 我们就已经将 Koa 相关的介绍与解析讲完了 。 我在写下来本文章的过程中 , 会对整个过程更加理解 , 也希望对你有所帮助!