Typescript中的通用中间件模式
|
2024年11月15日 21:35
本文热度 13
|
我实现的中间件模式与 Express、Koa 类似。基于一个 context
进行操作,并使用这个 context
作为参数按顺序运行一系列中间件。另外还传递一个 next
函数。如果调用了这个 next
函数,列表中的下一个中间件将被调用;如果不调用,链将被中断。此外,(与 Express 不同,但与 Koa 类似)中间件可以是 async
函数或返回一个 Promise。
准备工作
首先描述中间件:
/**
* 传递给中间件的 'next' 函数
*/
type Next = () => void | Promise<void>;
/**
* 一个中间件
*/
type Middleware<T> =
(context: T, next: Next) => Promise<void> | void;
Middleware
是实际的异步/非异步中间件函数。我为 Next
定义了一个类型,这样就不需要多次编写它了。
如何使用它
假设我们有一个“应用程序”、一组中间件和一个我们想要操作的上下文。通过以下代码表示:
/**
* 应用程序的上下文类型。
* 在 'koa' 中,这个对象将持有对 'request' 和 'response' 的引用,
* 但我们的上下文只有一个属性。
*/
type MyContext = {
a: number;
}
/**
* 创建应用程序对象
*/
const app = new MwDispatcher<MyContext>();
/**
* 一个中间件
*/
app.use((context: MyContext, next: Next) => {
context.a += 1;
return next();
});
/**
* 一个异步中间件
*/
app.use(async (context: MyContext, next: Next) => {
// 等待 2 秒
await new Promise(res => setTimeout(res, 2000));
context.a += 2;
return next();
});
运行这个应用程序
const context: MyContext = {
a: 0,
}
await app.dispatch(context);
console.log(context.a); // 应该输出 3
实现
实现这一切的代码非常简洁:
/**
* 中间件容器和调用器
*/
class MwDispatcher<T> {
middlewares: Middleware<T>[];
constructor() {
this.middlewares = [];
}
/**
* 添加一个中间件函数。
*/
use(...mw: Middleware<T>[]): void {
this.middlewares.push(...mw);
}
/**
* 在给定的上下文中按添加顺序执行中间件链。
*/
dispatch(context: T): Promise<void> {
return invokeMiddlewares(context, this.middlewares)
}
}
/**
* 在上下文中调用中间件链的辅助函数。
*/
async function invokeMiddlewares<T>(context: T, middlewares: Middleware<T>[]): Promise<void> {
if (!middlewares.length) return;
const mw = middlewares[0];
return mw(context, async () => {
await invokeMiddlewares(context, middlewares.slice(1));
})
}
该文章在 2024/11/16 8:51:53 编辑过