Koa
实例化
const app = new Koa()
this.middleware = [] // 通过实例的 use 方法增加
this.context = Object.create(context)
this.request = Object.create(request)
this.response = Object.create(response)
监听
listen (...args) {
const server = http.createServer(this.callback())
return server.listen(...args)
}
this.callback()
callback () {
// 聚合函数: 将全部中间件整合成一个函数;
const fn = compose(this.middleware)
// 请求回调
const handleRequest = (req, res) => {
// 整合 ctx(req res koa的一些针对请求和响应的方法)
const ctx = this.createContext(req, res)
return this.handleRequest(ctx, fn)
}
return handleRequest
}
handleRequest (ctx, fnMiddleware) {
const res = ctx.res
res.statusCode = 404 // 默认返回 404
const onerror = err => ctx.onerror(err)
const handleResponse = () => respond(ctx) // res.end(ctx.body)
// 执行全部的中间件(洋葱圈)
return fnMiddleware(ctx).then(handleResponse).catch(onerror)
}
洋葱模型
// 后面的中间件先resolve,然后再一个个resolve上来;
function compose (middleware) {
// 最终收到用户的请求时会执行这个
return function (context, next/* router中间件会传入这个 */) {
let index = -1
// 从第一个开始执行
return dispatch(0)
function dispatch (i) {
index = i
let fn = middleware[i]
// 这句router模块会用到
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
// 包一层 promise
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
}
}
}
// 看个例子
app.use(async (ctx, next) => {
console.log(1)
// 这里是 await 所以会等后面的resolve才继续向下执行
const res = await next()
// 等后面的中间件都resolve,才能拿到结果执行
console.log(res)
})
koa-router
app.use(router.routes()) // 路由中间件
// 执行 router 的get post等方法,会将回调push进 stack;
// 执行 dispatch
var dispatch = function dispatch(ctx, next) {
if (!matched.route) return next()
layerChain = matchedLayers.reduce(function(memo, layer) {
memo.push(function(ctx, next) {
ctx.captures = layer.captures(path, ctx.captures);
ctx.params = layer.params(path, ctx.captures, ctx.params);
ctx.routerName = layer.name;
return next();
});
return memo.concat(layer.stack);
}, []);
// 执行中间件 这个 next 是router中间件后面那个中间件的执行函数,注意不是一个维度
return compose(layerChain)(ctx, next);
};