koa-compose 是koa 框架的根源的根源 ,是其实现洋葱包裹型中间件的基础数组
如下是koa2.X 版本因此依赖的compose 版本 ,其主要核心依赖于new Promise.resolve();遍历 middleware 中间件集合,经过递归的方式来让每一个prmise按步执行promise
注:koa每添加一个中间件实则相 ,给koa对象的middleware 中间件数组push一个新值;缓存
//koa 对象的use方法最核心代码use(fn) { this.middleware.push(fn); return this; }
function compose (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) { //设置初始下标 let index = -1 //直接执行dispatch,而且从中间件数组下标0处开始执行中间件; return dispatch(0); /** * dispatch 函数,属于内部核心模块 */ function dispatch (i) { //合理性判断,若是若是参数小于等于下标就说明当前中间件被屡次执行则抛出异常 if (i <= index) return Promise.reject(new Error('next() called multiple times')) index = i // 对已参数为下标的当前中间件进行局部缓存 let fn = middleware[i] // 判断是否已到达中间件数组末尾,若是到达末尾则 返回不带参数的promise if (i === middleware.length) fn = next if (!fn) return Promise.resolve() try { //正常状况函数执行最终返回带有回调的promise,而且其参数就为某一个中间件 return Promise.resolve(fn(context, function next () { return dispatch(i + 1) })) } catch (err) { return Promise.reject(err) } } } }
第一次,此时第一个中间件被调用,dispatch(0),展开:框架
Promise.resolve(function(context, next){ //中间件一第一部分代码 await/yield next(); //中间件一第二部分代码 }());
很明显这里的next指向dispatch(1),那么就进入了第二个中间件;koa
第二次,此时第二个中间件被调用,dispatch(1),展开:异步
Promise.resolve(function(context, 中间件2){ //中间件一第一部分代码 await/yield Promise.resolve(function(context, next){ //中间件二第一部分代码 await/yield next(); //中间件二第二部分代码 }()) //中间件一第二部分代码 }());
很明显这里的next指向dispatch(2),那么就进入了第三个中间件;函数
第三次,此时第二个中间件被调用,dispatch(2),展开:this
Promise.resolve(function(context, 中间件2){ //中间件一第一部分代码 await/yield Promise.resolve(function(context, 中间件3){ //中间件二第一部分代码 await/yield Promise(function(context){ //中间件三代码 }()); //中间件二第二部分代码 }) //中间件一第二部分代码 }());