今天给大家搬运的是利用发布-订阅模式对代码进行解耦

你是否在项目封装的通用代码里这么干过,或者公司目前的代码就是这么做的呢?

举个栗子✏️

公司里的中后台项目封装的通用http库里请求响应拦截器是不是类似大概这样写的?

特别是如果在后端的响应码很多需要分开写逻辑时

js 复制代码
...
import router from '@/router'
import {Modal,message} from 'ant-design-vue'
export class Request {
  instance: AxiosInstance;
  baseConfig: AxiosRequestConfig = {
    baseURL: import.meta.env.VITE_APP_BASE_API,
    timeout: 100000 * 60 * 3 * 100,
  };

  constructor(config: AxiosRequestConfig) {
    this.instance = axios.create(Object.assign(this.baseConfig, config));
    this.instance.interceptors.request.use(
      (_config: AxiosRequestConfig) => {
        ...
        return _config;
      },
      (error: AxiosError) => Promise.reject(error)
    );

    this.instance.interceptors.response.use(
      (response: AxiosResponse) => {
        return response;
      },
      async (error: any) => {
       const data = error?.response?.data
        if (data && data.code === 60009) {
          ...
          Modal.error(...)
        }
        if (data && data.code === 60010) {
        ...
          message.warn(...)
        }
        if (error.response.status === 401) {
          router.push('/login')
        }
        ...
        return Promise.reject(error.response);
      }
    );
  }

这样的话一个网络请求库耦合的东西就太多而显得臃肿。

我们想一个网络请求库它就只需要做网络请求相关的工作就行了,没必要一会儿又需要引入UI组件弹窗显示,一会儿又要引入路由的方法进行跳转

像这样✨

1️⃣ 假如401需要跳转登录页面,触发一个需要路由去处理的事件,然后路由模块自己去接收处理

2️⃣ 假如60009需要UI组件message发出一个警告的提示就触发一个需要UI弹窗组件需要处理的事件,自己去处理

3️⃣ 假如600010需要UI组件Modal发出弹窗确认,触发一个事件,UI组件相应自己去接收处理

......

js 复制代码
  async (error: any) => {
        const data = error?.response?.data
        if (data && data.code === 60009) {
          emit()
        }
        if (data && data.code === 60010) {
          EventEmitter.emit('UI:OPEN_MESSAGE',...)
        }
        if (axios.isCancel(error)) return
        if (error.response.status === 401) {
         EventEmitter.emit('API:UN_AUTH')
        }
        if (data && (data.code ===1||data.code===50002)) {
           EventEmitter.emit('UI:OPEN_MESSAGE',...)
        }
        if (data && data.code !== 60009&&data.code !== 60010) {
             EventEmitter.emit('UI:OPEN_MODAL',...)
        }
        。。。
        return Promise.reject(error.response)
      }

EventEmitter⭐

js 复制代码
const eventNames = ["API:UN_AUTH", "API:INVALID_TOKEN","UI:OPEN_MESSAGE","UI:OPEN_MODAL" ,"..."] as const;
type EventName = (typeof eventNames)[number];

class EventEmitter {
  private listeners: Record<EventName, Set<Function>> = {
    "API:UN_AUTH": new Set(),
    "API:INVALID_TOKEN": new Set(),
  };
  on(eventNames: EventName, listener: Function) {
    this.listeners[eventNames].add(listener);
  }
  emit(eventNames: EventName, ...args: any[]) {
    this.listeners[eventNames].forEach((cb) => cb(...args));
  }
}

export default new EventEmitter();

导出一个全局的EventEmitter,在需要触发和需要订阅的模块引入使用

router

js 复制代码
import eventEmitter from '@utils/EventEmitter'
...
eventEmitter.on('API:UN_AUTH',()=>{
router.push('/login')
})
...

uiUtils

js 复制代码
import eventEmitter from '@utils/EventEmitter'
import {message,Modal} from 'ant-design-vue'
...
eventEmitter.on('UI:OPEN_MESSAGE',(...args)=>{
  message.wran({
  ...
  })
})
eventEmitter.on('UI:OPEN_MODAL',(...args)=>{
  Modal.wran({
  ...
  })
})
...

总结❤️

✅通过这样就能使用发布-订阅模式对业务代码逻辑进行充分解耦拉,也可以在你觉得很臃肿的很多其他业务代码里使用。

✅这样不仅仅又多掌握并运用了一种设计模式在今后吹嘘项目时也可以说自己的项目引入了发布订阅的模式进行代码解耦

相关推荐
天平8 小时前
油猴脚本创建webworker踩坑记录
前端·javascript·typescript
原则猫10 小时前
前端基础大厦
前端
陈随易11 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
SoaringHeart12 小时前
Flutter进阶:基于 EasyRefresh 的下拉刷新封装 n_easy_refresh_mixin.dart
前端·flutter
IT_陈寒14 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰14 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
山河木马15 小时前
渲染管线-计算得到gl_Position(顶点着色器)之后续GPU流程
javascript·webgl·图形学
竹林81815 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花15 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu122716 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude