@koa中间件 源码分析
[email protected]中间价源码分析
不废话直接
上代码
。
'use strict'
/**
* Expose compositor.
*/
module.exports = compose
/**
* Compose `middleware` returning
* a fully valid middleware comprised
* of all those which are passed.
*
* @param {Array} middleware
* @return {Function}
* @api public
*/
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!')
}
/**
* context 是传入的上下文数据 在中间件被执行时都可以访问到
* next 是中间都被执行完后 被执行的回调函数
*/
return function (context, next) {
/**
* 作为开始和结束的开关
*/
let index = -1
function dispatch(i) {
/**
* 如果 传入的 i 值 小于或等于 index 直接退出
*/
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
/**
* 给index赋值当前的i的值
*/
index = i
/**
* 创建fn变量为传入中间件数组的第i个
*/
let fn = middleware[i]
/**
* 如果 i 和 中间件数组的长度相等 说明是中间件函数已经执行完毕
* 给fn变量重新赋值为next
*/
if (i === middleware.length) fn = next
/**
* 如果fn是空的时候 退出这个中间件的执行
*/
if (!fn) return Promise.resolve()
try {
/**
* 返回一个Promise成功对象
* fn 为 中间件方法
* 值为 中间件方法执行
* 传入fn函数执行时传入的参数context
* dispatch.bind(null, i + 1)) === next 方法为 调用下一个中间件执行
*/
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
/**
* 捕获到错误直接退出中间件执行
*/
return Promise.reject(err)
}
}
return dispatch(0)
}
}
const middleware = [
function (context, next) {
console.log(context, 'context')
console.log(1, 'middleware')
next()
},
function (context, next) {
console.log(context, 'context')
console.log(2, 'middleware')
next()
},
function (context, next) {
console.log(context, 'context')
console.log(3, 'middleware')
next()
},
]
/**
* 第一个参数为中间件数组
* 第二参数为context
*/
compose(middleware)('我是帅哥', () => {
console.log('结束了')
})