Last active
June 8, 2024 01:28
-
-
Save nuintun/5be8ab4fdcef8b2bbaf95803e809b698 to your computer and use it in GitHub Desktop.
不会因未调用 next 而被打断的 compose 方法,可用于实现洋葱圈结构式的插件组合
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @module compose | |
*/ | |
interface CallStack { | |
index: number; | |
} | |
export interface Next { | |
(): Promise<void>; | |
} | |
export interface Composed<C> { | |
(context: C, next?: Next): Promise<void>; | |
} | |
export interface Middleware<C> { | |
(context: C, next: Next): Promise<void> | void; | |
} | |
/** | |
* @function dispatch | |
* @param middlewares 中间件数组 | |
* @param index 要执行的中间件索引 | |
* @param stack 调用栈信息 | |
* @param context 执行上下文 | |
* @param [next] 下一个中间件 | |
*/ | |
async function dispatch<C>( | |
middlewares: Middleware<C>[], | |
index: number, | |
stack: CallStack, | |
context: C, | |
next?: Next | |
): Promise<void> { | |
if (index <= stack.index) { | |
throw new Error('next() called multiple times'); | |
} | |
stack.index = index; | |
const { length } = middlewares; | |
if (index < length) { | |
const middleware = middlewares[index]; | |
await middleware(context, () => { | |
return dispatch(middlewares, index + 1, stack, context, next); | |
}); | |
if (stack.index + 1 < length) { | |
await dispatch(middlewares, stack.index + 1, stack, context, next); | |
} | |
} else if (next) { | |
await next(); | |
} | |
} | |
/** | |
* @function compose | |
* @description 生成融合中间件 | |
* @param middlewares 中间件数组 | |
*/ | |
export default function compose<C>(middlewares: Middleware<C>[]): Composed<C> { | |
/** | |
* @function middleware | |
* @description 融合中间件 | |
* @param context 执行上下文 | |
* @param [next] 下一个中间件 | |
*/ | |
return (context, next) => { | |
const stack = { index: -1 }; | |
return dispatch<C>(middlewares, 0, stack, context, next); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment