前言
一提到“发布订阅者模式”我就会想到eventBus,但 eventEmitter这个词我还是第一次见到,它和eventBus难道不是一个东西么?
eventBus的实现原理
class EventBus {
constructor() {
this.events = {};
}
//订阅
subscribe(names, cb) {
this.events[names] = this.events[names] || []
this.events[names].push(cb)
}
//发布
publish(names, val) {
if (!this.events[names]) {
return
}
this.events[names].forEach(callback => callback(val))
}
//取消
unsubscribe(names, cb) {
if (!this.events[names]) {
return
}
this.events[names] = this.events[names].filter(item => item !== cb)
}
}
//使用
let eventBus = new EventBus()
function cb1(...args) {
console.log("你好1", ...args)
}
function cb2(...args) {
console.log("你好2", args)
}
//订阅
eventBus.subscribe('event1', cb1)
eventBus.subscribe('event1', cb2)
eventBus.subscribe('event2', cb2)
//发布
eventBus.publish('event1', [1, 2, 3]) //你好1 [ 1, 2, 3 ] 你好2 [ 1, 2, 3 ]
eventBus.publish('event1', '我是测试二') // 你好1 我是测试二 你好2 我是测试二
//取消
eventBus.unsubscribe('event1', cb1)
eventBus.publish('event1', [1, 2, 3]) //你好2 [ 1, 2, 3 ]
eventEmitter的实现原理
class EventEmitter {
constructor() {
this._events = {};
}
// //注册事件
// on(eventName, cb) {
// const cbs = this._events[eventName] || []; //若本身注册过,则取之前的值,否则置为空数组
// cbs.push(cb);
// this._events[eventName] = cbs;
// }
// //发布订阅,并调度执行
// emit(eventName, ...args) {
// const cbs = this._events[eventName] || [];
// //将调度中心同名注册下的所有事件都执行一遍
// cbs.forEach((cb) => cb(...args));
// }
// off(eventName, cb) {
// const cbs = this._events[eventName] || [];
// //第二个并级判断,是为了配合once的特殊注册
// this._events[eventName] = cbs.filter(
// (filtItem) => filtItem !== cb && filtItem.cb !== cb
// );
// }
// //思想:在执行一次过后就将对应函数off掉
// once(eventName, cb) {
// const one = (...args) => {
// cb(...args);
// this.off(eventName, one);
// };
// //此处非常重要,若不添加,则在once注册之后,emit之前就off则无法删除对应注册回调
// one.cb = cb;
// this.on(eventName, one);
// }
//订阅
on(eventName, cb) {
this._events[eventName] = this._events[eventName] || []
this._events[eventName].push(cb)
}
//发布
emit(eventName, ...args) {
this._events[eventName] = this._events[eventName] || []
this._events[eventName].forEach(callback => {
callback(...args)
})
}
//取消
off(eventName, cb) {
this._events[eventName] = this._events[eventName] || []
this._events[eventName] = this._events[eventName].filter(item != cb && item.cb != cb)
}
//一次(执行一次后自动取消)
once(eventName, cb) {
const one = (...args) => {
cb(...args)
//off
this.off(eventName, one);
}
one.cb = cb //此处特别需要注意
this.on(eventName, one)
}
}
const events = new EventEmitter();
function handleName(name) {
console.log("name1", name);
}
function handleName2(name) {
console.log("name2", name);
}
events.on("hello", handleName);
events.once("hello", handleName2);
//此时once注册的时候存储的回调函数跟实际传递的回调函数是不相等的,在没有emit之前就直接off,是没有办法删除的
events.off("hello", handleName2);
events.emit("hello", "小明");
events.emit("hello", "小王");
两者的区别
从实现原理上面看,其实两个并没有什么区别
在实际使用当中:
`eventBus` 的使用范围更加广泛,可以跨越不同组件和模块之间进行信息通信传递,它是一个全局概念的事件总线。通常作为一个单例对象存在,因此往往需要创建一个中央管理器的实例
`EventEmitter` 是一个基于类的模块,用于在单个组件或模块内部实现事件的发布和订阅。所以它可以在需要的地方创建实例对象,并将其用于内部事件的发布和订阅