Koa 解析


Koa 解析文章插图
Koa 介绍在 Koa 的官网上 , slogan 是: 基于 Node.js 平台的下一代 Web 开发框架。 我们都知道 ,Koa 与 Express 都诞生自同一个团队 。 如何解析这个 slogan?
【Koa 解析】该 slogan 中所有包含“比较”含义的词汇 , 都可以理解为是相对 Express 而言的 。 所谓的"下一代""更小""更快" , 都特有所指 。 我们来看看现阶段 Express 与 Koa 的下载量对比:
Koa 解析文章插图
可以看出 , Express 的市场占有量与下载量(以及增速)都远远高于 Koa 。 所以自称为“下一代”并不为过(当然 , 这个数据层面来对比是否公平 , 值得商榷) 。
同时 , 与 Express 内部囊括了一套基础的业务处理框架的做法不同 , Koa 只包含了被称为“洋葱圈模型”的中间件核心处理逻辑 。 Koa 期望由社区来健全完善更多的业务模块 。 这样看来 , 将 Koa 看做 Express 之前内置的 Connect 来对比更合适(Express 4 内部已经移除 Connect) 。 不过 , “更小”的 Koa 定位更加明确 , 其内部一些突出的特性也让开发者感到欢喜 。
接下来 , 我们就来详细看看 Koa 相比于 Express 有什么不同?只有理解了不同 , 我们才会更加理解 Koa 的特性 。
自我定位在 Koa 官方网页上 , 有这样一段关于 Koa 定位的描述:
Philosophically, Koa aims to "fix and replace node", whereas Express "augments node". Koa uses promises and async functions to rid apps of callback hell and simplify error handling. It exposes its own ctx.request and ctx.response objects instead of node's req and res objects.Express, on the other hand, augments node's req and res objects with additional properties and methods and includes many other "framework" features, such as routing and templating, which Koa does not.摘抄网络上的一段翻译如下:
从理念上来说 , Koa 意图“修复并取代 node” , 而 Express 做的是“增强 node” 。 Koa 使用 promise 和 async 函数来摆脱回调地狱并简化异常处理逻辑 。 它暴露了自身的 ctx.request 和 ctx.response 对象而取代了 node 的 req 和 res 对象 。
Express 从另一方面 , 通过增加额外的属性和方法增强了 node 的 req 和 res 对象 , 并引入了许多框架上的功能 , 例如路由和模板 , 而 Koa 没有这么做 。
其实现是否符合定位 , 各位可自行看待 。
中间件处理逻辑在本质上 , Koa 与 Express 4 的区别在于下面两个点:

  • Koa 是使用 Promise + async/await 来处理中间件传递逻辑;而 Express 4 是使用回调函数来处理中间件传递逻辑 。
  • Koa 是走完所有的中间件处理逻辑才最终返回请求;而 Express 4 是遇到 res.send() 就返回请求 。
借助于新 ES 规范中 async/await 写法的 Promise 支持 , Koa 能够完美支持异步处理方式与摆脱回调地狱 。 下面的模拟实现 , 看代码的区别就可以体会到两者的不同之处 。
// express 与 Koa 在处理中间件逻辑上的底层模拟// express:回调函数app.use(function middleware1(req, res, next) {console.log('middleware1 开始')// next()(function (req, res, next) {console.log('middleware2 开始')// next()(function (req, res, next) {console.log('middleware3 开始')// next()(function handler(req, res, next) {res.send("end")console.log('123456')})()console.log('middleware3 结束')})()console.log('middleware2 结束')})()console.log('middleware1 结束')})// Koa: 基于 Promise + async/awaitfunction compose() {return function () {const ctx = {}// 每一次调用 next() , 都包了一层 Promise.resolvePromise.resolve(function fn1(context){console.log("middleware1 开始");yield Promise.resolve(function fn2(context){console.log("middleware2 开始");yield Promise.resolve(function fn3(context){console.log("middleware3 开始");yield Promise.resolve(function fn4(context){// ...more});console.log("middleware3 结束");});console.log("middleware2 结束");})console.log("middleware1 结束");});}}