Vue、React应用中的发布订阅模式实践,让你的代码像恋爱一样甜蜜!
发布订阅模式是一种常用的设计模式,也被称为观察者模式。它定义了一种对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会自动得到通知并更新自己的状态。
工作原理
在发布订阅模式中,有两个角色:发布者和订阅者。发布者负责发布消息,而订阅者则负责订阅消息并处理相应的逻辑。发布者和订阅者之间没有直接的联系,它们之间的通信是通过事件机制来实现的。
具体来说,发布者维护一个事件列表,当某个事件发生时,它会遍历事件列表,将事件的信息发送给所有订阅了该事件的订阅者。订阅者通过订阅事件来表达自己的兴趣,并在事件发生时得到通知,从而执行相应的处理逻辑。
使用场景
发布订阅模式的主要作用是解耦,它将发布者和订阅者之间的依赖关系通过事件机制进行解耦,使得它们之间可以独立地变化。因此,发布订阅模式适用于以下场景:
- 在一个系统中,当一个对象的状态发生改变时,需要通知其他多个对象进行相应的处理,但又不希望这些对象直接耦合在一起,这时可以使用发布订阅模式来实现。
- 当一个对象需要被多个其他对象观察时,可以使用发布订阅模式来实现对象间的通信。
- 当一个对象需要观察多个其他对象时,可以使用发布订阅模式来实现对这些对象的观察。
- 当一个对象需要异步处理某些操作,并在处理完成后通知其他对象时,可以使用发布订阅模式来实现异步通信。
在JavaScript中,事件驱动编程(Event-driven programming)是一个非常常见的场景,如浏览器中的DOM事件、Node.js中的事件机制、React中的组件通信等,都可以使用发布订阅模式来实现。
在原生代码中的使用示例
下面是一个使用JavaScript实现发布订阅模式的示例:
// 发布者
class Publisher {
constructor() {
this.subscribers = {};
}
// 添加订阅者
subscribe(event, callback) {
if (!this.subscribers[event]) {
this.subscribers[event] = [];
}
this.subscribers[event].push(callback);
}
// 删除订阅者
unsubscribe(event, callback) {
if (!this.subscribers[event]) {
return;
}
const index = this.subscribers[event].indexOf(callback);
if (index !== -1) {
this.subscribers[event].splice(index, 1);
}
}
// 发布消息
publish(event, data) {
if (!this.subscribers[event]) {
return;
}
this.subscribers[event].forEach(callback => {
callback(data);
});
}
}
// 订阅者
class Subscriber {
constructor(name) {
this.name = name;
}
// 处理消息
handleMessage(data) {
console.log(`${this.name} received: ${data}`);
}
}
// 创建发布者和订阅者
const publisher = new Publisher();
const subscriber1 = new Subscriber('subscriber1');
const subscriber2 = new Subscriber('subscriber2');
// 添加订阅者
publisher.subscribe('event1', subscriber1.handleMessage.bind(subscriber1));
publisher.subscribe('event1', subscriber2.handleMessage.bind(subscriber2));
// 发布消息
publisher.publish('event1', 'Hello, world!');
// 删除订阅者
publisher.unsubscribe('event1', subscriber1.handleMessage.bind(subscriber1));
// 再次发布消息
publisher.publish('event1', 'Goodbye, world!');
在上述示例中,我们定义了一个Publisher
类和一个Subscriber
类,其中Publisher
负责发布消息,Subscriber
负责订阅消息并处理相应的逻辑。
在Publisher
类中,我们使用一个对象subscribers
来保存订阅者,subscribe()
方法用于添加订阅者,unsubscribe()
方法用于删除订阅者,publish()
方法用于发布消息。
在Subscriber
类中,我们定义了一个handleMessage()
方法用于处理消息。
在示例中,我们创建了一个Publisher
实例和两个Subscriber
实例,并将Subscriber
实例添加为Publisher
实例的订阅者。然后,我们发布了一个event1
事件的消息,并在两个订阅者中分别处理该消息。接着,我们删除了一个订阅者,并再次发布了一个event1
事件的消息,此时只有一个订阅者收到了该消息。
在vue中使用
在Vue中,可以使用内置的事件机制实现发布订阅模式。Vue实例有一个$emit
方法用于触发事件,并且可以使用$on
方法监听事件。下面是一个使用Vue实现发布订阅模式的示例:
// 创建一个事件总线
const bus = new Vue();
// 订阅者组件
const subscriber = Vue.component('subscriber', {
data() {
return {
message: ''
}
},
mounted() {
// 监听事件
bus.$on('event1', this.handleMessage);
},
methods: {
// 处理消息
handleMessage(data) {
this.message = data;
}
},
template: `
<div>
<p>Message: {{ message }}</p>
</div>
`
});
// 发布者组件
const publisher = Vue.component('publisher', {
methods: {
// 发布消息
publishMessage() {
bus.$emit('event1', 'Hello, world!');
}
},
template: `
<div>
<button @click="publishMessage">Publish Message</button>
</div>
`
});
// 创建Vue实例
const app = new Vue({
el: '#app',
components: {
subscriber,
publisher
},
template: `
<div>
<subscriber></subscriber>
<publisher></publisher>
</div>
`
});
在示例中,我们首先创建了一个事件总线bus
,然后定义了一个订阅者组件subscriber
和一个发布者组件publisher
。在订阅者组件中,我们使用bus.$on
方法监听event1
事件,并在方法中处理消息。在发布者组件中,我们使用bus.$emit
方法发布event1
事件。
最后,我们在Vue实例中使用了订阅者组件和发布者组件,并将它们渲染到页面中。当点击“Publish Message”按钮时,将会触发publisher
组件的publishMessage
方法,从而发布event1
事件,订阅者组件会接收到该事件并处理相应的逻辑。
在React中使用
在React中,可以使用第三方库如pubsub-js
实现发布订阅模式,也可以自己手动实现。下面是一个手动实现的示例:
// 创建一个事件总线
const eventBus = {
events: {},
subscribe(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
},
unsubscribe(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
},
publish(event, data) {
if (this.events[event]) {
this.events[event].forEach(cb => cb(data));
}
}
};
// 订阅者组件
class Subscriber extends React.Component {
constructor(props) {
super(props);
this.state = {
message: ''
};
this.handleMessage = this.handleMessage.bind(this);
}
componentDidMount() {
// 监听事件
eventBus.subscribe('event1', this.handleMessage);
}
componentWillUnmount() {
// 取消监听
eventBus.unsubscribe('event1', this.handleMessage);
}
handleMessage(data) {
this.setState({ message: data });
}
render() {
return (
<div>
<p>Message: {this.state.message}</p>
</div>
);
}
}
// 发布者组件
class Publisher extends React.Component {
constructor(props) {
super(props);
this.publishMessage = this.publishMessage.bind(this);
}
publishMessage() {
// 发布事件
eventBus.publish('event1', 'Hello, world!');
}
render() {
return (
<div>
<button onClick={this.publishMessage}>Publish Message</button>
</div>
);
}
}
// 渲染组件
ReactDOM.render(
<div>
<Subscriber />
<Publisher />
</div>,
document.getElementById('root')
);
在示例中,我们首先创建了一个事件总线eventBus
,其中包含了subscribe
、unsubscribe
和publish
三个方法。然后定义了一个订阅者组件Subscriber
和一个发布者组件Publisher
,在订阅者组件中,我们使用eventBus.subscribe
方法监听event1
事件,并在方法中处理消息。在发布者组件中,我们使用eventBus.publish
方法发布event1
事件。
最后,我们通过ReactDOM.render
方法将订阅者组件和发布者组件渲染到页面中。当点击“Publish Message”按钮时,将会触发Publisher
组件的publishMessage
方法,从而发布event1
事件,订阅者组件会接收到该事件并处理相应的逻辑。
在Node中的使用
在Node.js中使用发布订阅模式和在浏览器端类似,也需要手动实现一个事件总线对象。可以通过创建一个全局的事件管理器对象来实现发布订阅模式,代码如下:
const eventEmitter = require('events'); // 引入events模块
const eventBus = new eventEmitter(); // 创建事件总线对象
// 发布事件
eventBus.emit('eventName', eventData);
// 订阅事件
eventBus.on('eventName', (eventData) => {
// 处理事件数据
});
// 取消订阅事件
eventBus.off('eventName', callback);
在这里,我们使用了Node.js内置的events
模块来创建一个事件管理器对象,并通过emit
、on
和off
等方法来实现事件的发布、订阅和取消订阅。
在具体的应用场景中,我们可以将事件总线对象作为参数传递给需要进行通信的模块或组件,从而实现它们之间的通信。同时,我们还可以在事件总线对象上定义不同的事件,用于传递不同类型的数据,提高应用的灵活性和可维护性。
总之,在Node.js中使用发布订阅模式需要创建一个事件总线对象,并通过其提供的方法来实现事件的发布、订阅和取消订阅。在具体应用时,我们可以将事件总线对象作为参数传递给需要通信的模块或组件,实现它们之间的通信。
总结
发布订阅模式是一种常用的设计模式,它通过解耦发布者和订阅者之间的关系来实现组件之间的通信,从而提高应用的灵活性和可维护性。在实现发布订阅模式时,通常需要创建一个事件总线,其中包含了subscribe
、unsubscribe
和publish
等方法来实现订阅和发布事件。在Vue和React中,我们可以使用第三方库如vue-bus
和pubsub-js
来实现发布订阅模式,也可以手动实现。无论是使用第三方库还是手动实现,发布订阅模式都是一种非常实用的设计模式,能够在组件间的通信中发挥重要作用。
转载自:https://juejin.cn/post/7228787506191892540