深入理解与手写发布订阅模式
🤍 前端开发工程师、技术日更博主、已过CET6
🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1
🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》
🍚 蓝桥云课签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》
文章目录
- 引言
- 发布订阅模式的基本概念
- 手写发布订阅模式的实现步骤
- 1. 定义事件中心类
- 2. 实现订阅方法(`on`)
- 3. 实现发布方法(`emit`)
- 4. 实现取消订阅方法(`off`)
- 使用示例
- 总结
引言
在软件开发领域,发布订阅模式(Publish-Subscribe Pattern)是一种广泛应用的设计模式,它在解耦组件之间的依赖关系、实现事件驱动的编程方面发挥着重要作用。通过这种模式,不同的组件可以在不直接依赖对方的情况下进行通信和交互,从而提高系统的可维护性和扩展性。本文将详细介绍发布订阅模式的概念、原理,并通过手写代码来深入理解其实现过程。
发布订阅模式的基本概念
发布订阅模式包含三个主要角色:发布者(Publisher)、订阅者(Subscriber)和事件中心(Event Center)。
- 发布者:负责产生事件,并将事件发布到事件中心。它并不关心哪些订阅者会处理这些事件。
- 订阅者:向事件中心订阅特定类型的事件,当该类型的事件被发布时,订阅者会接收到通知并执行相应的处理逻辑。
- 事件中心:作为发布者和订阅者之间的中介,它维护着事件与订阅者之间的映射关系,当接收到发布者发布的事件时,会将事件通知给所有订阅了该事件的订阅者。
手写发布订阅模式的实现步骤
1. 定义事件中心类
首先,我们需要定义一个事件中心类,用于管理事件和订阅者。
class EventEmitter {constructor() {// 使用对象存储事件和对应的订阅者数组this.events = {};}
}
在上述代码中,我们创建了一个 EventEmitter
类,其构造函数初始化了一个空的 events
对象,用于存储不同事件类型及其对应的订阅者数组。
2. 实现订阅方法(on
)
接下来,我们为事件中心类添加一个 on
方法,用于订阅事件。
class EventEmitter {constructor() {this.events = {};}on(eventName, callback) {// 如果事件不存在,则初始化一个空数组来存储订阅者if (!this.events[eventName]) {this.events[eventName] = [];}// 将回调函数添加到对应事件的订阅者数组中this.events[eventName].push(callback);return this;}
}
on
方法接收事件名称 eventName
和回调函数 callback
作为参数。如果该事件名称在 events
对象中不存在,则创建一个空数组。然后将回调函数添加到对应事件的订阅者数组中,并返回 this
,以便支持链式调用。
3. 实现发布方法(emit
)
然后,实现 emit
方法,用于发布事件。
class EventEmitter {constructor() {this.events = {};}on(eventName, callback) {if (!this.events[eventName]) {this.events[eventName] = [];}this.events[eventName].push(callback);return this;}emit(eventName, ...args) {// 获取对应事件的订阅者数组const callbacks = this.events[eventName];if (callbacks && callbacks.length > 0) {// 依次执行每个订阅者的回调函数,并传递参数callbacks.forEach(callback => callback(...args));}return this;}
}
emit
方法接收事件名称 eventName
和任意数量的参数 ...args
。它首先获取对应事件的订阅者数组,如果数组存在且不为空,则遍历数组并依次执行每个订阅者的回调函数,同时将参数传递给回调函数。
4. 实现取消订阅方法(off
)
为了使订阅者能够取消订阅事件,我们还需要实现一个 off
方法。
class EventEmitter {constructor() {this.events = {};}on(eventName, callback) {if (!this.events[eventName]) {this.events[eventName] = [];}this.events[eventName].push(callback);return this;}emit(eventName, ...args) {const callbacks = this.events[eventName];if (callbacks && callbacks.length > 0) {callbacks.forEach(callback => callback(...args));}return this;}off(eventName, callback) {const callbacks = this.events[eventName];if (callbacks) {// 找到并删除对应的回调函数const index = callbacks.indexOf(callback);if (index!== -1) {callbacks.splice(index, 1);}}return this;}
}
off
方法接收事件名称 eventName
和要取消订阅的回调函数 callback
。它先获取对应事件的订阅者数组,然后在数组中查找回调函数的索引,如果找到则使用 splice
方法将其从数组中删除。
使用示例
// 创建事件中心实例
const emitter = new EventEmitter();// 订阅事件
const callback1 = function(data) {console.log('Callback 1:', data);
};
emitter.on('event1', callback1);// 发布事件
emitter.emit('event1', 'Hello, World!');// 取消订阅
emitter.off('event1', callback1);// 再次发布事件,已取消订阅的回调函数不会被执行
emitter.emit('event1', 'Another message');
在上述示例中,我们首先创建了一个 EventEmitter
实例 emitter
,然后订阅了一个名为 event1
的事件,并定义了一个回调函数 callback1
。接着发布了 event1
事件,回调函数被执行并输出相应信息。之后取消了对 event1
事件的订阅,再次发布 event1
事件时,已取消订阅的回调函数不再被执行。
总结
通过手写实现发布订阅模式,我们深入理解了其核心原理和实现细节。发布订阅模式通过事件中心有效地解耦了发布者和订阅者之间的依赖关系,使得系统更加灵活和可扩展。在实际开发中,这种模式广泛应用于各种场景,如前端框架中的事件系统、后端服务之间的通信等。掌握发布订阅模式,有助于我们编写更加健壮和高效的软件系统。