Open chenfei-hnu opened 5 years ago
koa使用洋葱模型进行中间件调用,执行时类型函数内调用函数形成执行上下文栈依次调用 koa1基于的co库,所以koa1利用Generator来代替回调,而koa2由于node对async/await的支持,所以koa2利用的是async/await 与express相比,洋葱模型后置处理逻辑的编码更加方便,异常处理用try catch更自然,Context 提供更多的node原生功能
1.中间件是generator函数,作为use参数传入middleware数组,函数中使用yield next来执行后面的中间件
2.使用compose使用while call的方式倒叙循环,将后面的中间件作为next参数与之前的中间件绑定,第一个执行的最后的中间件传入一个noop作为其next,形成串联关系
3.将compose返回的generator函数作为参数调用co,done为false时,判断有value.next即为yield next,递归调用co(value.next),在.then的resolve中递归next(data)继续执行原中间件后续逻辑,形成洋葱模型 done为false时,判断有value.then即需要执行异步操作,也在.then的resolve中递归next(data)继续执行当前中间件后续逻辑,done为false时,没有value.next及value.then即为普通的暂停,递归next(data)继续执行即可
const middleware = []; const use = (fn) => { middleware.push(fn); } function* noop() {} const co = (it) => { return new Promise((resolve, reject) => { function next(data) { let { value, done } = it.next(); if (!done) { if (value.next) { co(value).then(() => { next(data); }); } else if (value.then) { value.then(() => { next(data); }) } else { next(data); } } else { resolve(value); } } next(); }); } const compose = (middleware) => { return function* (next) { if (!next) next = noop(); let index = middleware.length; while (index--) { next = middleware[index].call(this, next); } yield* next; } } use(function* (next) { console.log(1); yield next; console.log(2); }); const asyncPromise = (timeout) => { return new Promise((resolve) => { setTimeout(() => { resolve(); }, timeout) }); } use(function* (next) { console.log(3); const data = yield asyncPromise(1000); yield next; console.log(4); }); use(function* () { yield 1; console.log(5); }); const gen = compose(middleware); co(gen());
const middleware = []; const use = (fn) => { middleware.push(fn); } const asyncPromise = (timeout) => { return new Promise((resolve) => { setTimeout(() => { resolve(); }, timeout) }); } use(async (ctx, next) => { console.log("中间件1 start"); await asyncPromise(1000); await next(); console.log("中间件1 end"); }) use(async (ctx, next) => { console.log("中间件2 start"); await asyncPromise(1000); await next(); console.log("中间件2 end"); }) use(async (ctx, next) => { console.log("中间件3 start"); await asyncPromise(1000); await next(); console.log("中间件3 end"); }) const compose = (middleware) => { return (ctx, response) => { const dispatch = (i) => { let fn = middleware[i]; if (i === middleware.length) fn = response; if (!fn) return Promise.resolve() return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1))) } return dispatch(0); } } compose(middleware)(null, () => { console.log('success'); });
koa1
1.中间件是generator函数,作为use参数传入middleware数组,函数中使用yield next来执行后面的中间件
2.使用compose使用while call的方式倒叙循环,将后面的中间件作为next参数与之前的中间件绑定,第一个执行的最后的中间件传入一个noop作为其next,形成串联关系
3.将compose返回的generator函数作为参数调用co,done为false时,判断有value.next即为yield next,递归调用co(value.next),在.then的resolve中递归next(data)继续执行原中间件后续逻辑,形成洋葱模型 done为false时,判断有value.then即需要执行异步操作,也在.then的resolve中递归next(data)继续执行当前中间件后续逻辑,done为false时,没有value.next及value.then即为普通的暂停,递归next(data)继续执行即可
koa2