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

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

举个栗子✏️

公司里的中后台项目封装的通用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({
  ...
  })
})
...

总结❤️

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

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

相关推荐
xianxin_3 分钟前
CSS Outline(轮廓)
前端
moyu843 分钟前
遮罩层设计与实现指南
前端
Sammyyyyy9 分钟前
2025年,Javascript后端应该用 Bun、Node.js 还是 Deno?
开发语言·javascript·node.js
timeweaver18 分钟前
深度解析 Nginx 前端 location 配置与优先级:你真的用对了吗?
前端·nginx·前端工程化
鲸落落丶19 分钟前
网络通信---Axios
前端
wwy_frontend21 分钟前
React性能优化实战:从卡顿到丝滑的8个技巧
前端·react.js
小高00736 分钟前
面试官:npm run build 到底干了什么?从 package.json 到 dist 的 7 步拆解
前端·javascript·vue.js
天选打工圣体37 分钟前
个人学习笔记总结(四)抽离elpis并发布npm包
前端
wayhome在哪1 小时前
用 fabric.js 搞定电子签名拖拽合成图片
javascript·产品·canvas
JayceM2 小时前
Vue中v-show与v-if的区别
前端·javascript·vue.js