koa使用
koa是个微小的web框架。
第一步:安装koa包
npm i koa
第二步:测试代码
const Koa = require('koa');
const app = new Koa();
app.use((ctx, next) => {
const start = new Date().getTime();
console.log(`start: ${ctx.url}`);
// next()执行下一个中间件
await next();
const end = new Date().getTime();
console.log(`请求${ctx.url},耗时 ${end-start}ms`);
})
app.use((ctx, next) => {
ctx.body = [{
name: 'abc'
}]
await next();
})
app.listen(3000)
koa使用中间件的概念来实现切面编程AOP。中间件的执行类似于剥洋葱的操作,层层深入。
手写koa
第一步:简单手写koa框架源码
文件名为koa.js,代码如下:
// koa.js
const http = require('http');
const request = require('./request.js'); // 见第二步request.js代码
const response = require('./response.js'); // 见第二步response.js代码
const context = require('./context.js'); // 见第二步context.js代码
class KOA {
// 初始化中间件数组
constructor(){
this.middlewares = [];
}
// 启动服务,端口监听
listen(...args){
const server = http.createServer((req, res) => {
// 创建上下文
const ctx = this.createContext(req, res);
// 中间件组合
const fn = this.compose(this.middlewares); // compose函数定义见第三步-中间件代码
// 执行中间件
await fn(ctx);
// 响应
ctx.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;
}
}
module.exports = KOA;
第二步:Context上下文的封装
定义context上下文对象,将request, response对象封装起来,内部使用get() 和 set()简化字段的调用。
request.js 代码如下:
// request.js
module.exports = {
get url(){
return this.req.url;
},
get method(){
return this.req.method.toLowerCase();
}
}
response.js 代码如下:
// response.js
module.exports = {
get body(){
return this._body;
},
set body(val){
this._body = val;
}
}
context.js 代码如下:
// 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;
}
}
第三步:中间件代码
简易版
简易版compose同步函数组合实现原理:
// 同步函数组合
function compose(...[first, ...other]){
return (...args) => {
let res = first(...args);
other.forEach(fn => {
res = fn(res);
})
return res;
}
}
洋葱圈版
middleware实现原理,组合函数代码如下:
// 中间件组合函数
function 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(){
// promise完成后,再执行下一个
return dispatch(i+1);
})
)
}
}
}
async function a(next){
console.log('aa');
await next();
console.log('aa end');
}
async function b(next){
console.log('bb');
await next();
console.log('bb end');
}
async function c(next){
console.log('cc')
await next()
console.log('cc end')
}
let funcs = compose([a, b, c])
funcs();
// 打印结果如下:
aa
bb
cc
cc end
bb end
aa end
第四步:调用框架代码
文件名为test.js,代码如下:
// test.js
const KOA = require('./koa.js');
const app = new KOA();
app.use(ctx => {
ctx.body('hello world');
})
app.listen(3000);
koa优点
相比原生http的优点:
- 解决response, request的api不优雅的问题。koa 包装了context 上下文机制。
- 解决复杂问题的逻辑描述问题。koa使用了洋葱圈的中间件机制,既可以做切面编程,也可以顺序流转。
资料来源于网上学习资料,技术搬运工一枚。