发布订阅模式:
订阅者把自己想订阅的事件注册到调度中心,当发布者发布该事件到调度中心,也就是该事件触发时,由调度者统一调度订阅者注册到调度中心的处理代码。
在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)
})
}
}
}