用发布订阅模式解耦
举一个常见的例子,网络模块和 UI 模块耦合。
封装 axios
request.ts
// ...
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response.status === 401) {
message.error("登录失效,请重新登录"); // 与 UI 模块耦合
router.push("/login"); // 与路由模块耦合
}
}
);
可以看到,网络模块和 UI 模块、路由模块耦合了。
解耦
没有什么事情是加一个中间层解决不了的,如果有,那就再加一个。
eventCenter.ts
const eventNames = ["API:UNAUTHORIZED", "API:FORBIDDEN"] as const;
type EventName = (typeof eventNames)[number];
class EventCenter {
private events: Record<EventName, Set<Function>> = {
"API:UNAUTHORIZED": new Set(),
"API:FORBIDDEN": new Set(),
};
// 订阅事件
on(eventName: EventName, callback: Function) {
this.events[eventName].add(callback);
}
// 触发事件
emit(eventName: EventName, ...args: any[]) {
this.events[eventName].forEach((callback) => callback(...args));
}
}
export default new EventCenter();
request.ts
import eventCenter from "./eventCenter";
axios.interceptors.response.use(
(response) => response,
(error) => {
if (error.response.status === 401) {
// 触发事件
eventCenter.emit("API:UNAUTHORIZED");
} else if (error.response.status === 403) {
// 触发事件
eventCenter.emit("API:FORBIDDEN");
}
return Promise.reject(error);
}
);
router.ts
import eventCenter from "./eventCenter";
// 订阅事件
eventCenter.on("API:UNAUTHORIZED", () => {
router.push("/login");
});
message.ts
import eventCenter from "./eventCenter";
// 订阅事件
eventCenter.on("API:UNAUTHORIZED", () => {
message.error("登录失效,请重新登录");
});
总结
发布订阅模式是一种解耦的常用手段,它通过一个事件中心来管理事件的订阅和发布,从而避免了模块之间的直接耦合。