new Koa()里面初始化了一堆变量,其中最为重要的是context,request和response,里面的作用等会再看,先看app.use()代码。
app.use()
1 2 3 4 5 6 7 8 9 10 11 12
use(fn) { if (typeof fn !== 'function') thrownewTypeError('middleware must be a function!'); if (isGeneratorFunction(fn)) { deprecate('Support for generators will be removed in v3. ' + 'See the documentation for examples of how to convert old middleware ' + 'https://github.com/koajs/koa/blob/master/docs/migration.md'); fn = convert(fn); } debug('use %s', fn._name || fn.name || '-'); this.middleware.push(fn); returnthis; }
functioncompose(middleware) { if (!Array.isArray(middleware)) thrownewTypeError("Middleware stack must be an array!"); for (const fn of middleware) { if (typeof fn !== "function") thrownewTypeError("Middleware must be composed of functions!"); }
returnfunction(context, next) { // last called middleware # let index = -1; return dispatch(0); functiondispatch(i) { if (i <= index) returnPromise.reject(newError("next() called multiple times")); index = i; let fn = middleware[i]; if (i === middleware.length) fn = next; if (!fn) returnPromise.resolve(); try { returnPromise.resolve(fn(context, dispatch.bind(null, i + 1))); } catch (err) { returnPromise.reject(err); } } }; }
可以看到返回一个方法,里面其实是递归执行,从dispatch(0)开始执行,然后到return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));不断递归,假设已经middleware.length最后一个,那么就返回一个Promise.resolve();,也就是这段代码实现了洋葱圈模型,也就是app.use里面的next参数实际上是执行之后的middleware,这里有个官方 gif 图讲述这个过程。