发布-订阅
模式也是经典的设计模式
之一,它在前端很多地方都有应用,比如javascript事件池
,Vue的$on、$off
,nodejs的events模块和socket通信
等等都有应用,也是前端面试比较火热的考点之一,接下来给大家详细介绍下发布-订阅模式
发布-订阅模式定义了对象间的一种一对多的依赖关系
,当一个对象的状态发生变化时,所有依赖它的对象都将得到通知
。在JavaScript开发中,我们一般用事件模型来替代传统的发布-订阅模式
要手写一个简单的发布订阅模式,其实现思路如下:
- 先初始化一个
events对象
- 调用
on
方法时,将事件名称eventName
和监听函数fn
存入events对象
中 - 调用
emit
方法时,通过事件名称eventName
从events对象
中取出对应的回调并执行 off
方法:通过事件名称eventName
找出events对象
对应的监听函数并清除once
方法:被emit
触发一次后就立即调用off
方法移除监听,也就是调用once
传入的监听函数只会执行一次
代码不多,所以直接上完整代码
class EventEmitter {
constructor() {
this.events = {}
}
on(eventName, fn) {
if (!this.events[eventName]) {
this.events[eventName] = []
}
this.events[eventName].push(fn)
console.log(this,'this')
return this
}
once(eventName, fn) {
const func = (...args) => {
this.off(eventName, func)
fn.apply(this, args)
}
this.on(eventName, func)
return this
}
emit(eventName, ...args) {
if (!this.events[eventName]) return this
this.events[eventName].forEach(fn => {
fn.apply(this, args)
});
return this
}
off(eventName, fn) {
if (!this.events[eventName]) return this
if (typeof fn === 'function') {
this.events[eventName] = this.events[eventName].filter((f) => f !== fn)
return this
}
this.events[eventName] = null
return this
}
}
const events = new EventEmitter();
events.on('event1', () => {
console.log('event1', '第一个监听函数')
})
events.on('event1', () => {
console.log('event1', '第二个监听函数')
})
events.emit('event1')
const fn1 = () => {
console.log('event2', '第一个监听函数')
}
const fn2 = () => {
console.log('event2', '第二个监听函数')
}
events.on('event2', fn1)
events.on('event2', fn2)
events.off('event2', fn1);
// 打印结果:
// event1 第一个监听函数
// event1 第二个监听函数
// 上面代码有疑问请阅读下面代码,这部分解答了上面读者的疑问
const events = new EventEmitter();
// event1部分
events.on('event1', () => {
console.log('event1', '第一个监听函数')
})
events.on('event1', () => {
console.log('event1', '第二个监听函数')
})
events.emit('event1')
// event2部分
const fn1 = () => {
console.log('event2', '第一个监听函数')
}
const fn2 = () => {
console.log('event2', '第二个监听函数')
}
events.on('event2', fn1)
events.off('event2', fn1);
events.on('event2', fn2)
events.emit('event2')
- 可以广泛应用于异步编程中,这是一种替代传递回调函数的方案;
- 可以取代对象之间硬编码的通知机制,一个对象不用再显示地调用一个对象的接口