主题
发布订阅模式
概念
一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知
和观察者模式的区别:发布者不直接触及到订阅者、而是由统一的第三方来完成实际的通信的操作
EventEmitter
js
class EventEmitter{
constructor() {
this.events = {} // 维护一个对象
}
/**
* 订阅
* @param {类型名} name
* @param {订阅的方法} fn
*/
on(name, fn) {
if (!this.events[name]) {
this.events[name] = []
}
this.events[name].push(fn)
}
/**
* 只订阅一次
* @param {类型名} name
* @param {订阅的方法} fn
*/
once(name, fn) {
const wrapper = (...args) => {
fn(...args)
this.off(name, wrapper)
}
this.on(name, wrapper)
}
/**
* 发布
* @param {类型名} name
* @param {传入的参数} args
*/
emit(name, ...args) {
if (this.events[name]) {
// 做一次浅拷贝,主要目的是为了避免通过 once 安装的监听器在移除的过程中出现顺序问题
const events = this.events.slice()
events[name].forEach(item => {
item.apply(this, args)
})
}
}
/**
* 移除类型
* @param {类型名} name
*/
remove(name){
if (this.events[name]) {
delete this.events[name]
}
}
}
然后就可以愉快的使用了,创建一个 js/ts
文件,在文件中创建一个实例
js
const EventBus = new EventEmitter()
export default EventBus
订阅事件:
js
import bus from '@/event-emitter.js'
bus.on('name', fn)
发布(触发)事件:
js
import bus from '@/event-emitter.js'
bus.emit('name', params)
VUE 双向绑定
首先会有一个 observer(监听器),这个 observer 不是观察者,他是发布订阅模式里的第三方
当数据又改变会被 observer 看见,也就是触发 emit,然后 observer 就会通知底下的 dep
实现订阅者 Dep:
js
class Dep {
constructor() {
// 初始化订阅队列
this.subs = []
}
// 增加订阅者
addSub(sub) {
this.subs.push(sub)
}
// 通知订阅者(是不是所有的代码都似曾相识?)
notify() {
this.subs.forEach((sub)=>{
sub.update()
})
}
}
实现监听器 observer
js
// observe方法遍历并包装对象属性
function observe(target) {
// 若target是一个对象,则遍历它
if(target && typeof target === 'object') {
Object.keys(target).forEach((key)=> {
// defineReactive方法会给目标属性装上“监听器”
defineReactive(target, key, target[key])
})
}
}
// 定义defineReactive方法
function defineReactive(target, key, val) {
// 属性值也可能是object类型,这种情况下需要调用observe进行递归遍历
observe(val)
// 为当前属性安装监听器
Object.defineProperty(target, key, {
// 可枚举
enumerable: true,
// 不可配置
configurable: false,
get: function () {
return val;
},
// 监听器函数
set: function (value) {
val = value
dep.notify()
}
});
}