它能接受一个函数数组,然后返回一个新的函数,
函数自外向内,然后自内向外执行,和洋葱一样
例如:
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); }); } } }
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'); });*/ }
处理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); }