1. 最近学习后端,发现koa里边有个use函数挺有意思
const MiniKoa =require("./koa")
const app =new MiniKoa();
app.use((ctx,next)=>{
console.log(1);
ctx.body="123";
next();
console.log(2);
})
app.use((ctx,next)=>{
console.log(3);
ctx.body+="123"
next();
console.log(4);
})
app.listen(7999)
当请请求到达node服务器时 依次打印 1 3 4 2 ,神奇就神奇在这个洋葱模型,由外而内再由内而外
隐隐约约感觉这个use是把函数推进一个队列,然后next指向下一个中间件
2.根据外部调用实现里边的封装,一下是两个关键点
2.1 context 上下文的封装 (上下文应该是每次请求都不一样,所以一定是用new的方式)
class Ctx {
constructor(req, res) {
this.req = req;
this.res = res;
this.body = null;
}
}
2.2 next函数的实现用的是compose封装
function compose(middlewares) {
return function (ctx) {
const dispatch = (i) => {
if (i == middlewares.length) {
return ()=>{}
}
else {
//参照中间件写法 app.use( (ctx,next)=>{***});
return middlewares[i](ctx, ()=>{dispatch(i + 1)})
}
}
//返回第一个中间件
return dispatch(0)
}
}
2.3 koa的封装
class MiniKoa {
constructor() {
this.middlewares = []
}
listen(...arg) {
var server = http.createServer(async (req, res) => {
//console.log("请求来了",req.url)
const ctx = new Ctx(req, res)
const fn = compose(this.middlewares)
try {
await fn(ctx)
ctx.res.end(ctx.body)
} catch (err) {
this.onerror(ctx, err)
}
})
server.listen(...arg)
}
onerror(ctx, err) {
console.log(err)
}
//没错 use就是把所有的中间件推进队列
use(fn) {
if (Object.prototype.toString.call(fn) === '[object Function]') {
this.middlewares.push(fn)
} else {
throw new Error('use arguments must be a function')
}
}
}
3.完整代码
const http = require("http")
class Ctx {
constructor(req, res) {
this.req = req;
this.res = res;
this.body = null;
}
}
//多函数连接式
function compose(middlewares) {
return function (ctx) {
const dispatch = (i) => {
if (i == middlewares.length) {
return ()=>{}
}
else {
return middlewares[i](ctx, ()=>{dispatch(i + 1)})
}
}
return dispatch(0)
}
}
class MiniKoa {
constructor() {
this.middlewares = []
}
listen(...arg) {
var server = http.createServer(async (req, res) => {
// res.end(JSON.stringify({ code: 'ok', data: { user: "张三" } }))
console.log("请求来了",req.url)
const ctx = new Ctx(req, res)
const fn = compose(this.middlewares)
try {
await fn(ctx)
ctx.res.end(ctx.body)
} catch (err) {
this.onerror(ctx, err)
}
})
server.listen(...arg)
}
onerror(ctx, err) {
console.log(err)
}
use(fn) {
if (Object.prototype.toString.call(fn) === '[object Function]') {
this.middlewares.push(fn)
} else {
throw new Error('use arguments must be a function')
}
}
}
module.exports= MiniKoa