关于EventBus事件总线
- 事件总线,实现 on, once, emit, off
- on, once 是注册函数,存储起来
- emit时找到对应的函数,执行
- off找到对应的函数,从对象中删除
- 注意
- 区分on和once
- on绑定的事件可连续执行,除非off
- once绑定的函数 emit 一次即删除,也可未执行而被 off
- 数据结构上标识出 on 和 once
实现方案1
代码实现:使用参数区分 on和once
ts
class EventBus {
/*
{
key1: [
{fn: fn1, isOnce: false},
{fn: fn2, isOnce: false},
{fn: fn3, isOnce: true},
],
key2: []
}
*/
private events: {
[key: string]: Array<{fn: Function; isOnce: boolean}>
}
constructor() {
this.events = {};
}
on(type: string, fn: Function, isOnce: boolean = false) {
const events = this.events;
if (events[type] == null) {
events[type] = []; // 初始化 key 的 fn 数组
}
events[type].push({fn, isOnce});
},
// 这里是初步版本
once_origin(type: string, fn: Function) {
const events = this.events;
if (events[type] == null) {
events[type] = []; // 初始化 key 的 fn 数组
}
events[type].push({fn, isOnce: true});
},
once(type: string, fn: Function, isOnce: boolean = false) {
this.on(type, fn, true);
},
off(type: string, fn?:Function) {
if (!fn) {
// 解绑所有 type 的函数
this.events[type] = [];
} else {
// 解绑单个 fn
const fnList = this.events[type];
if (fnList.length) {
this.events[type] = fnList.filter(item.fn !== fn);
}
}
},
emit(type: string, ...args: any[]) {
const fnList = this.events[type];
if (fnList == null) return;
// 注意
this.events[type] = fnList.filter(item => {
const { fn, isOnce } = item;
fn(...args);
// 处理once, 它执行一次就要被过滤掉
if (!isOnce) return true;
return false;
})
}
}
const e = new EventBus();
function fn1(a: any, b: any) {console.log('fn1', a, b)};
function fn2(a: any, b: any) {console.log('fn2', a, b)};
function fn3(a: any, b: any) {console.log('fn3', a, b)};
e.on('key1', fn1);
e.on('key1', fn2);
e.once('key1', fn3);
e.emit('key1', 10, 20); // 触发 fn1, fn2, fn3
e.off('key1', fn1);
e.emit('key1', 100, 200); // 触发 fn2
实现方案2
代码实现: 拆分保存 on和once
js
class EventBus {
private events: { [key: string]: Array<Function>} // {key1: [fn1, fn2]}
private onceEvents: {[key: string]: Array<Function>} // 结构同上
constructor() {
this.events = {}; // 存储 on
this.onceEvents = {}; // 存储 once
}
// on 触发
on(type: string, fn: Function) {
const events = this.events;
if (events[type] === null) events[type] = [];
events[type].push(fn);
},
once(type: string, fn: Function) {
const onceEvents = this.onceEvents;
if (onceEvents[type] === null) onceEvents[type] = [];
onceEvents[type].push(fn);
},
// 解绑事件
off(type: string, fn: Function) {
if (!fn) {
// 解绑所有事件
this.events[type] = [];
this.onceEvents[type] = [];
} else {
// 解绑单个
const fnList = this.events[type];
const onceFnList = this.onceEvents[type];
if (fnList.length) {
this.events[type] = fnList.filter(curFn => curFN!== fn);
}
if (onceFnList.length) {
this.onceEvents[type] = onceFnList.filter(curFn => curFN!== fn);
}
}
},
emit(type: string, ...args: any[]) {
const fnList = this.events[type];
const onceFnList = this.onceEvents[type];
if (fnList.length) {
fnList.forEach(f => f(...args));
}
if (onceFnList.length) {
onceFnList.forEach(f => f(...args));
// once 执行一次就删除,这里更简单,代码更简洁
this.onceEvents[type] = [];
}
}
}
// 测试用例同上,此处省略
总结
- 区分 on, once
- 合理的数据结构,比算法优化更有效