Koa
是由Express
原班人马打造,可是相较于Express
的大而全,Koa
是小而精的。Koa
没有绑定不少的框架以及插件,更容易让咱们进行扩展,包括如今较为流行的EggJS
and ThinkJS
都是基于Koa
开发的。Koa
避免了Express中间件基于callback形式的调用,它使用了咱们JS新版本特性,Koa1
中间件借助于咱们的co
and generator
特性,Koa2
借助了Promise
and async await
特性,更好的进行流程控制以及catch咱们的错误。Koa
提供了Context
对象,其实是对咱们node中request
and response
对象的封装,咱们不须要不少的手动处理咱们的request
and response
对象。Context
是贯穿咱们整个请求的过程,咱们能够中间件须要传递参数挂在到Context
对象上。(栗子:咱们能够将用户信息挂在它上面,经过ctx.state.user
进行操做。)Koa
的中间件执行机制:洋葱圈模型
。它不是按顺序执行的,多个中间件会造成一个先进后出
的栈结构,当前中间件掌握下一个中间件的执行权,对于流程控制以及后置处理逻辑的实现很是有效。Koa1
借助co
and generator
管理咱们的中间件,Koa2
借助async await
(async函数返回的是Promise
对象)管理咱们的中间件。context
对象获取:Koa1
经过this
对象(this.req
,this.res
)获取,Koa2
经过ctx
参数(ctx.req
, ctx.res
)获取。Koa2
的轮子多且成熟,生态比Koa1
丰富。listen
方法建立了咱们的http服务器,端口是
3000
。而且经过
use
方法传入了三个
koa
中间件, 而且
console
出咱们的执行结果。
listen
方法提及lib
文件,咱们在栗子中require('koa')
其实是引入的lib/application.js
里面的Application
类。下面咱们来分析一下咱们的listen
方法的实现,首先咱们看一下这个Application
类里面到底有些什么:Application
类下有咱们的listen
方法,方法以下:listen
方法里面的
this.callback()
实际上也返回是一个函数,这个函数接收req、res两个入参。
this.callback()
里的callback方法是啥样的:这个方法接收两个参数: 一个是咱们的compose的返回结果fn、另外一个是咱们的ctx对象,这个方法主要是对咱们请求的处理以及错误的统一捕获以及处理。javascript
Koa的中间件执行机制有个形象的称呼-洋葱圈模型。咱们先执行栗子代码,看看输出的结果究竟是什么? 前端
再回到上文提到的callback函数,咱们的中间件执行机制的核心就是compose(this.middleware),下面咱们来分析一下compose函数的源码: java
Promise.reslove()
。// Promise.reslove返回一个fulfillled状态的promise对象
// 能够当作new Promise()的快捷方式
Promise.reslove(fn(context, dispatch.bind(null, i+1)));
// 其实是等于
new Promise((relove, reject) => {
reslove(fn(context, dispatch.bind(null, i+1)));
})
复制代码
Promise.reslove(fn(context, dispatch.bind(null, i + 1)))
, 这个fn(context, dispatch.bind(null, i + 1))
也就是执行咱们经过app.use
加入的middleware函数,middleware函数统一接收两个参数一个是context,一个是next:下一个middleware函数,这样能够看出来若是咱们koa中某个中间件没有执行next方法,那么以后加入的中间件是不会执行的。这也就造成了咱们的洋葱圈模型
。// 核心方法:递归调用咱们middlewares, 基于Promise进行异步流程控制;
// Promise.resolve()返回的是一个thenable对象;
// 因此咱们koa2中中间件都基于async函数,await等待下个中间件方法的执行;
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'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
复制代码
先进后出
的栈结构,当前中间件掌握下一个中间件的执行权。Koa1
借助co
and generator
管理咱们的中间件,Koa2
借助async await
(async函数返回的是Promise
对象)管理咱们的中间件。这是一个全栈开发实战实例:koa2-mysql-sequelize-JWT(供参考交流,一块儿学习)。node
这是一个我的博客(前端修炼指南):front-end-Web-developer-interviewmysql