洋葱模型
它能接受一个函数数组,然后返回一个新的函数,
函数自外向内,然后自内向外执行,和洋葱一样
例如:
const fn1 = (next) => {
console.log(1);
next();
console.log(2);
};
const fn2 = (next) => {
console.log(3);
next();
console.log(4);
};
const fn3 = (next) => {
console.log(5);
next();
console.log(6);
};
const middlewares = [fn1, fn2, fn3];
compose(middlewares)(); //输出 1,3,5,6,4,2
实现compose,因为考虑到函数自外向内,然后自内向外执行,所以可以试下递归
function compose (composeList) {
return function () {
next(0);
async function next(i) {
if (i === composeList.length) {
return;
}
composeList[i](() => {
awaite next(i+1);
});
}
}
}
koa框架基本步骤
封装http server
class Application {
constructor() {
this.middlewares = [];
this.context = context;
this.request = request;
this.response = response;
}
/**
* 开启http server并传入callback
*/
listen(...args) {
let server = http.createServer(this.callback());
server.listen(...args);
}
/**
* 挂载回调函数
* @param {Function} fn 回调处理函数
*/
use(fn) {
this.middlewares.push(middleware);
}
//原生的
/* let server = http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world');
});
server.listen(3000, () => {
console.log('listenning on 3000');
});*/
}
封装request, response, context对象
处理url 以及 设置取值 body、status 以及给 context对象赋值
中间机制处理-----洋葱
/**
* 中间件合并方法,将中间件数组合并为一个中间件
* @return {Function}
*/
compose() {
// 将middlewares合并为一个函数,该函数接收一个ctx对象
return async ctx => {
function createNext(middleware, oldNext) {
return async () => {
await middleware(ctx, oldNext);
};
}
let len = this.middlewares.length;
let next = async () => {
return Promise.resolve();
};
for (let i = len - 1; i >= 0; i--) {
let currentMiddleware = this.middlewares[i];
next = createNext(currentMiddleware, next);
}
await next();
};
}
/**
* 获取http server所需的callback函数
* @return {Function} fn
*/
callback() {
return (req, res) => {
let ctx = this.createContext(req, res);
let respond = () => this.responseBody(ctx);
let one rror = (err) => this.onerror(err, ctx);
let fn = this.compose();
// 在这里catch异常,调用onerror方法处理异常
return fn(ctx).then(respond).catch(onerror);
};
}
/**
* 构造ctx
* @param {Object} req node req实例
* @param {Object} res node res实例
* @return {Object} ctx实例
*/
createContext(req, res) {
// 针对每个请求,都要创建ctx对象
let ctx = Object.create(this.context);
ctx.request = Object.create(this.request);
ctx.response = Object.create(this.response);
ctx.req = ctx.request.req = req;
ctx.res = ctx.response.res = res;
return ctx;
}
错误处理
在回调函数中callback catch捕捉错误
/**
* 错误处理
* @param {Object} err Error对象
* @param {Object} ctx ctx实例
*/
one rror(err, ctx) {
if (err.code === 'ENOENT') {
ctx.status = 404;
}
else {
ctx.status = 500;
}
let msg = err.message || 'Internal error';
ctx.res.end(msg);
// 触发error事件
this.emit('error', err);
}