WHAT - 发布订阅

张裕  高级会员 | 2024-6-14 21:19:10 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 213|帖子 213|积分 639

在前端开辟中,发布订阅是一种常见的开辟场景,允许一个对象(发布者)发布变乱,而多个对象(订阅者)可以订阅并吸取这些变乱。
发布订阅在设计模式中,可以理解为 观察者模式 / Observer Pattern
一、常见实现方案

以下是一些常见的实现方案:
1.1 使用变乱发射器(Event Emitter)

许多 JavaScript 框架和库内置了变乱发射器机制,例如 Node.js 的 EventEmitter 类。
  1. const EventEmitter = require('events');
  2. const eventEmitter = new EventEmitter();
  3. // 定义事件
  4. eventEmitter.on('event', (data) => {
  5.   console.log('Event received:', data);
  6. });
  7. // 触发事件
  8. eventEmitter.emit('event', 'Hello World!');
复制代码
1.2 自定义变乱系统(EventBus)

本身实现一个简单的发布订阅系统,可以通过维护一个变乱监听器的映射表来实现。
  1. class EventBus {
  2.   constructor() {
  3.     this.listeners = {};
  4.   }
  5.   on(event, listener) {
  6.     if (!this.listeners[event]) {
  7.       this.listeners[event] = [];
  8.     }
  9.     this.listeners[event].push(listener);
  10.   }
  11.   emit(event, data) {
  12.     if (this.listeners[event]) {
  13.       this.listeners[event].forEach(listener => listener(data));
  14.     }
  15.   }
  16.   off(event, listener) {
  17.     if (this.listeners[event]) {
  18.       this.listeners[event] = this.listeners[event].filter(l => l !== listener);
  19.     }
  20.   }
  21. }
  22. const eventBus = new EventBus();
  23. eventBus.on('message', (data) => console.log('Message received:', data));
  24. eventBus.emit('message', 'Hello EventBus!');
复制代码
1.3 使用库如 PubSubJS

PubSubJS 是一个轻量级的 JavaScript 发布订阅库。
  1. const PubSub = require('pubsub-js');
  2. // 订阅
  3. const token = PubSub.subscribe('TOPIC', (msg, data) => {
  4.   console.log(msg, data);
  5. });
  6. // 发布
  7. PubSub.publish('TOPIC', 'Hello PubSubJS!');
  8. // 取消订阅
  9. PubSub.unsubscribe(token);
复制代码
1.4 使用框架内置的状态管理工具

许多现代前端框架如 Vue.js、React 和 Angular 提供了内置的状态管理工具,可以用来实现发布订阅模式。例如:
Vue.js

  1. const EventBus = new Vue();
  2. // 组件A:发布事件
  3. EventBus.$emit('myEvent', 'Hello from Component A');
  4. // 组件B:订阅事件
  5. EventBus.$on('myEvent', (data) => {
  6.   console.log(data);
  7. });
复制代码
React (使用 Context API 或 Redux)

  1. // 使用 Context API
  2. const MyContext = React.createContext();
  3. // 提供者组件
  4. const MyProvider = ({ children }) => {
  5.   const [state, setState] = useState(null);
  6.   const publish = (data) => {
  7.     setState(data);
  8.   };
  9.   return (
  10.     <MyContext.Provider value={{ state, publish }}>
  11.       {children}
  12.     </MyContext.Provider>
  13.   );
  14. };
  15. // 订阅者组件
  16. const MySubscriber = () => {
  17.   const { state, publish } = useContext(MyContext);
  18.   
  19.   useEffect(() => {
  20.     console.log('State updated:', state);
  21.   }, [state]);
复制代码
二、先后关系

可以先订阅后发布,那可以先发布后订阅吗?
在发布订阅模式中,先订阅后发布是非经常见的做法,因为这通常是实实际时变乱通知的根本方式:订阅者先准备好吸取消息,然后发布者发送消息
然而,某些情况下,也大概需要在没有订阅者存在的情况下发布消息,并且在订阅者稍后订阅时能够收到之前发布的消息。要实现这种“先发布后订阅”的机制,可以采用以下几种方法:
2.1 缓存变乱数据

发布者在发布消息时,将消息暂时存储在一个缓存中,当新的订阅者订阅时,可以将缓存中的消息发送给订阅者。
  1. class EventBus {
  2.   constructor() {
  3.     this.listeners = {};
  4.     this.cachedEvents = {};
  5.   }
  6.   on(event, listener) {
  7.     if (!this.listeners[event]) {
  8.       this.listeners[event] = [];
  9.     }
  10.     this.listeners[event].push(listener);
  11.    
  12.     // 如果有缓存的事件,立即触发
  13.     if (this.cachedEvents[event]) {
  14.       listener(this.cachedEvents[event]);
  15.     }
  16.   }
  17.   emit(event, data) {
  18.     if (this.listeners[event]) {
  19.       this.listeners[event].forEach(listener => listener(data));
  20.     }
  21.     // 缓存事件数据
  22.     this.cachedEvents[event] = data;
  23.   }
  24.   off(event, listener) {
  25.     if (this.listeners[event]) {
  26.       this.listeners[event] = this.listeners[event].filter(l => l !== listener);
  27.     }
  28.   }
  29. }
  30. const eventBus = new EventBus();
  31. // 发布事件
  32. eventBus.emit('message', 'This is a cached message');
  33. // 订阅事件
  34. eventBus.on('message', (data) => {
  35.   console.log('Message received:', data); // Output: 'This is a cached message'
  36. });
复制代码
2.2 使用 Redux 或 Vuex 等状态管理工具

在前端框架中使用状态管理工具,例如 Redux(React)或 Vuex(Vue.js),可以在状态发生变化时订阅并触发相应的处理逻辑。状态管理工具的状态是持久的,订阅者在任何时间都可以获取当前的状态。
Redux 示例
  1. const { createStore } = require('redux');
  2. // 定义 action 类型
  3. const SET_MESSAGE = 'SET_MESSAGE';
  4. // 定义 action 创建函数
  5. const setMessage = (message) => ({
  6.   type: SET_MESSAGE,
  7.   payload: message
  8. });
  9. // 定义 reducer
  10. const messageReducer = (state = null, action) => {
  11.   switch (action.type) {
  12.     case SET_MESSAGE:
  13.       return action.payload;
  14.     default:
  15.       return state;
  16.   }
  17. };
  18. // 创建 Redux store
  19. const store = createStore(messageReducer);
  20. // 订阅 store
  21. const unsubscribe = store.subscribe(() => {
  22.   const state = store.getState();
  23.   console.log('State updated:', state);
  24. });
  25. // 发布 action
  26. store.dispatch(setMessage('This is a Redux message'));
复制代码
2.3 使用本地存储或 IndexedDB

如果需要跨页面持久化数据,可以使用欣赏器的本地存储(LocalStorage)或 IndexedDB。发布者将消息存储到本地存储中,订阅者在订阅时从本地存储中读取数据。
  1. // 发布消息
  2. localStorage.setItem('message', 'This is a persisted message');
  3. // 订阅消息
  4. const cachedMessage = localStorage.getItem('message');
  5. if (cachedMessage) {
  6.   console.log('Message received:', cachedMessage);
  7. }
复制代码
通过这些方法,可以实现“先发布后订阅”的功能,确保订阅者能够收到之前发布的消息。选择哪种方法可以根据详细需求和技能栈来决定。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张裕

高级会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表