next是函数,返回的是
promise。
app.use(async (ctx, next) => { console.log(1); await next(); console.log(2);});use把函数放进
this.middleware中,
listen时,
compose是
koa-compose,转换。
class Application extends Emitter { // 代码有简化组合 listen(){ const fnMiddleware = compose(this.middleware); fnMiddleware(ctx).then(handleResponse).catch(onerror); }, use(fn){ this.middleware.push(fn); return this; }}koa-compose源码
function compose (middleware) { // 校验middleware 是数组和数组每一项都是函数的校验 if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!') for (const fn of middleware) { if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!') } return function (context, next) { // last called middleware # let index = -1 return dispatch(0) function dispatch (i) { if (i <= index) return Promise.reject(new Error('next() called multiple times')) index = i let fn = middleware[i] if (i === middleware.length) fn = next if (!fn) return Promise.resolve() try { return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); } catch (err) { return Promise.reject(err) } } }}移除一些校验和报错代码翻译下就是这样,也就是常说的洋葱模型。
// simpleKoaComposeconst [fn1, fn2, fn3] = this.middleware;const fnMiddleware = function(context){ return Promise.resolve( fn1(context, function next(){ return Promise.resolve( fn2(context, function next(){ return Promise.resolve( fn3(context, function next(){ return Promise.resolve(); }) ) }) ) }) );};fnMiddleware(ctx).then(handleResponse).catch(onerror);具体源码可以看我这篇文章。
若川:学习 koa 源码的整体架构,浅析koa洋葱模型原理和co原理



