什么是koa
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。
koa的特点
koa2完全使用Promise并配合 async 来实现异步 其特点是
-
轻量
-
无捆绑
-
中间件架构
-
优雅的API设计
-
增强的错误处理
koa 的实现
构造一个 koa 类
class KOA {
constructor(){
// middlewares 数组用于管理中间件函数
this.middlewares = []
}
listen(...args) {
// 服务器监听端口实现逻辑
}
// 添加中间件函数方法
use(middleware){
this.middlewares.push(middleware)
}
createContext(req, res) {
// 创建 context 上下文
}
compose(middlewares) {
// 实现洋葱圈模型
}
}
创建一个应用程序:
const app = new Koa();
-
KOA 类定义了 this.middlewares 数组来管理中间件函数;
-
app.listen() 方法创建了一个 HTTP 服务器;
-
app.use() 方法用于给 this.middlewares 添加中间件函数;
-
app.createContext() 方法引入上下文context的概念,将原始请求对象req和响应对象res封装并挂载到 context上,并且在context上设置getter和setter,从而简化操作;
-
app.compose() 方法则是洋葱圈模型的实现核心;
实现 listen 方法
listen(...args) {
const server = http.createServer(async (req, res) => {
// 创建上下文对象
const ctx = this.createContext(req, res);
// 中间件合成
const fn = this.compose(this.middlewares);
// 执行合成函数并传入上下文
await fn(ctx);
res.end(ctx.body);
})
// 监听端口
server.listen(...args)
}
实现 use 方法
use 方法的作用就是给 this.middlewares 添加中间件函数
use(middleware){
// 将中间件添加到数组里
this.middlewares.push(middleware)
}
实现 createContext 方法
构建上下文, 把res和req都挂载到ctx之上,并且在ctx.req和ctx.request.req同时保存。
createContext(req, res) {
const ctx = Object.create(context)
ctx.request = Object.create(request)
ctx.response = Object.create(response)
ctx.req = ctx.request.req = req
ctx.res = ctx.response.res = res
return ctx
}
实现 compose 方法
Koa中间件机制就是函数式组合概念 Compose 的概念,将一组需要顺序执行的函数复合为一个函数,外层函数的参数实际是内层函数的返回值。洋葱圈模型可以形象表示这种机制。
compose(middlewares) {
// 传入上下文对象
return function (ctx) {
// 执行第一个中间件函数
return dispatch(0)
// dispatch函数递归遍历 middleware,
// 然后将 context 和 dispatch(i + 1) 传给 middleware 中的方法
function dispatch(i) {
let fn = middlewares[i]
if (!fn) {
return Promise.resolve()
}
return Promise.resolve(
// 将上下文传入中间件 mid(ctx, next)
fn(ctx, function next() {
// 执行下一个中间件函数
return dispatch(i + 1)
})
)
}
}
}
封装 request、response 和 ontext
// request.js
module.exports = {
get url() {
return this.req.url;
},
get method() {
开课吧web全栈架构师
return this.req.method.toLowerCase()
}
};
// response.js
module.exports = {
get body() {
return this._body;
},
set body(val) {
this._body = val;
}
};
// context.js
module.exports = {
get url() {
return this.request.url;
},
get body() {
return this.response.body;
},
set body(val) {
this.response.body = val;
},
get method() {
return this.request.method
}
};
KOA 类的完整代码
const http = require('http')
const context = require('./context')
const request = require('./request')
const response = require('./response')
class KOA {
constructor(){
this.middlewares = []
}
listen(...args) {
const server = http.createServer(async (req, res) => {
// 创建上下文
const ctx = this.createContext(req, res)
const fn = this.compose(this.middlewares)
await fn(ctx)
res.end(ctx.body)
})
server.listen(...args)
}
use(middleware){
this.middlewares.push(middleware)
}
createContext(req, res) {
const ctx = Object.create(context)
ctx.request = Object.create(request)
ctx.response = Object.create(response)
ctx.req = ctx.request.req = req
ctx.res = ctx.response.res = res
return ctx
}
compose(middlewares) {
return function (ctx) {
return dispatch(0)
function dispatch(i) {
let fn = middlewares[i]
if (!fn) {
return Promise.resolve()
}
return Promise.resolve(
fn(ctx, function next() {
return dispatch(i + 1)
})
)
}
}
}
}
module.exports = KOA;
koa 使用
const KOA = require('./koa')
const app = new KOA()
const delay = () => Promise.resolve(resolve => setTimeout(() => resolve(), 2000));
app.use(async (ctx, next) => {
ctx.body = "1";
setTimeout(() => {
ctx.body += "2";
}, 2000);
await next();
ctx.body += "3";
});
app.use(async (ctx, next) => {
ctx.body += "4";
await delay();
await next();
ctx.body += "5";
});
app.use(async (ctx, next) => {
ctx.body += "6";
});