Skip to content

Instantly share code, notes, and snippets.

@nuintun
Last active June 8, 2024 01:28
Show Gist options
  • Save nuintun/5be8ab4fdcef8b2bbaf95803e809b698 to your computer and use it in GitHub Desktop.
Save nuintun/5be8ab4fdcef8b2bbaf95803e809b698 to your computer and use it in GitHub Desktop.
不会因未调用 next 而被打断的 compose 方法,可用于实现洋葱圈结构式的插件组合
/**
* @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