发布订阅模式:
订阅者把自己想订阅的事件注册到调度中心,当发布者发布该事件到调度中心,也就是该事件触发时,由调度者统一调度订阅者注册到调度中心的处理代码。
在javaScript 中我们一般使用事件模型来代替传统的发布订阅模式。
- 结构:在发布订阅模式中,有一个中介者来管理发布者和订阅者之间的关系。
- 关系:发布者和订阅者不直接耦合,他们通过中间进行通信。发布者将消息发布给中介者,然后中介者将消息传递给所有的订阅者。
- 通知方式:订阅者通过向中介者注册感兴趣的事件或主题,中介者在收到消息后负责将消息分发给所有的订阅者。
可以广泛应用于异步编程中,这是一种替代传递回调函数的方案。
可以取代对象之间硬编码的通知机制,一个对象不能再显示地调用另外一个对象的某个接口。
从建构上看,无论是MVC还是MVVM.都少不了发布订阅模式的参与,而且javaScript本身也是一门基于事件驱动的语言。
简单理解:
DOM 事件, js简单的发布订阅模式
document.getElementById('myBtn').addEventListener('click', function() {alert('hellow word!')
})
简单的发布订阅模式
中介者
let e = {_callback: [],on(callback) {// 订阅一件事,当这件事发生时,触发相应的函数// 订阅就是将函数放到数组中this._callback.push(callback)},emit(value) {this._callback.forEach(method => {method(value)})}
}
// 订阅
e.on(function(value) {console.log(value + 'aa的订阅')
})
// 订阅
e.on(function(value) {console.log(value + 'bb的订阅')
})
// 发布
e.emit('发布')
自定义事件
let salesOffices = {clientList: {}listen(key, fn) {if (!this.clientList[key]) {this.clientList[key] = []}this.clientList[key].push(fn)},tigger() { // 发布消息let key = Array.prototype.shift.call(arguments) // 取出消息类型 取出实参let fns = this.clientList[key]if (!fns || fns.length === 0) {return false}for(let fn of fns) {fn.apply(this, arguments) }}
}// 例子
salesOffices.listen('squareMeter88', price => console.log(`价格 = ${price}`))
salesOffices.listen('squareMether110', price => console.log(`价格 = ${price}`))salesOffices.trigger('squareMether88', 2000000)
salesOffices.trigger('squareMether110', 3000000)
通用的实现
通用的一种封装,实现了订阅、发布、取消
const event = {clientList: [],listen: function(key, fn) {if (!this.clientList[key]) {this.clientList[key] = []}this.clientList[key].push(fn)}trigger: function() {const key = Array.prototype.shift.call(arguments)const fns = this.clientList(key)if (!fns || fns.length === 0) {return false}for(let i = 0, fn; fn = fns[i++];) {fn.apply(this, arguments)}}remove: function(key, fn) {let fns = this.clientList[key];if (!fns) {return false}if (!fn) {fns && (fns.length = 0)} else {for(let i = fns.length -i; 1 >= 0; i-- ) {let _fn = fns[i]if (_fn === fn) {fns.splice(1,1)}}}}
}
const installEvent = function( obj ){obj = { ...obj, ...event }
};let salesOffices = {};
installEvent(salesOffices);salesOffices.listen( 'squareMeter88', fn1 = function(price){ // 小明订阅消息console.log('价格= ' + price);
});salesOffices.listen( 'squareMeter100', fn2 = function(price){ // 小红订阅消息console.log('价格= ' + price );
});salesOffices.remove('squareMeter88', fn1); // 删除小明的订阅salesOffices.trigger('squareMeter88', 2000000); // 输出:2000000
salesOffices.trigger('squareMeter100', 3000000); // 输出:3000000
Veu中使用发布订阅
vue 提供了一个简单的事件系统,通过 vm.$emit
发布事件,vm.$on
订阅事件。这种机制类似于发布-订阅模式,允许组件之间进行松散耦合的通信。
在vue 中使用发布订阅模式的例子:
使用EventBus: 你可以创建一个简单的EventBus, 用于在不同组件之间进行通信。
// EventBus.js
import Vue from 'vue'
export const EventBus = new Vue()// componentsA.vue
import { EventBus } from './EventBus'
export default {methods: {sendMessage() {EventBus.$emit('message', 'hello from ComponentA!')}}
}// componentsB.vue
import { EventBus } from './EventBus'
export default {methods: {sendMessage() {EventBus.$on('message', message => {console.log('Reveived message in ComponentB:', message)})}}
}