发布订阅模式中,包含发布者,事件调度中心,订阅者三个角色。发布者和订阅者是松散耦合的,互不关心对方是否存在,他们关注的是事件本身。发布者借用事件调度中心提供的emit方法发布事件,而订阅者则通过on进行订阅。
实现思路
- 创建一个类(EventEmitter)
- 在该类上创建一个对象(时间调度中心),用来存储所有事件
- on 方法用来把函数 fn 都加到对象中(订阅者注册事件到调度中心)
- emit 方法取第一个参数当作事件 event,根据 event 值去执行对象中对应的函数(发布者发布事件到调度中心,调度中心处理代码)
- off 方法可以根据 event 值取消订阅(取消订阅)
- once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)
- 注册一个 newListener 用于监听新的事件订阅
完整代码
class EventEmitter {
constructor () {
this.event = {};
}
on (name, callback) {
// 注册newListener监听新的事件订阅
if (this.event[name] && name !== 'newEventLister') {
this.emit('newEventLister', name);
}
// 一个事件可能有多次回调
const callbacks = this.event[name] || [];
callbacks.push(callback);
this.event[name] = callbacks;
}
emit (name, ...args) {
// 循环执行回调函数
let callbacks = this.event[name] || [];
callbacks.forEach(fn => {
fn(...args);
});
}
off (name, callback) {
let callbacks = this.event[name] || [];
// fn.initCallback !== callback 用于once的取消订阅
this.event[name] = callbacks.filter(fn => fn !== callback && fn.initCallback !== callback);
}
once (name, callback) {
// 在执行一次之后删除该函数
let oneFn = (...arg) => {
callback(...arg);
this.off(name, callback);
};
oneFn.initCallback = callback;
this.on(name, oneFn);
}
}
const newEvent = new EventEmitter();
let fn = (a) => { console.log(a); };
newEvent.on('fn', fn);
newEvent.on('fn', (a) => { console.log(a + 1); });
newEvent.emit('fn', '1');
newEvent.emit('fn', '2');
newEvent.off('fn', fn);
newEvent.emit('fn', '第三次');
newEvent.once('once', (a, b) => {
console.log(a + b);
});
newEvent.emit('once', 'name:', 'li');