前言
从来也没想着写些啥的,但是偶尔翻开以前的记录,发现忘了好多事,以后有空就记录一下吧。
发布订阅模式
今天看见一篇很好的文章,那第一篇文章就从抄开始吧,程序员一定要学会CV。文章来源:
希望作者大大勿怪。
效果演示
模拟接口请求的状态,并做相应处理。比如在监听到一个错误码,需要刷新页面的时候,发布订阅模式做为一个中间层。如果需要处理大量的状态码,这不失为一个好的方式。
代码
/**
* 扩展需要根据自身业务需求来定义
* 实现中使用 Set 存订阅事件及先发布后订阅的事件参数,想的是去重,
* 重复订阅事件, 先发布后订阅多次相同参数的事件 都只存一次
* 可以根据业务需求,来决定用Array存还是Set存
*/
type EventCallback = (...args: any[]) => void;
class EventManager {
static #instance: EventManager;
#listeners: Record<string, Set<EventCallback>> = {};
#pending: Record<string, Set<any[]>> = {}
private constructor() {}
static getInstance() {
return EventManager.#instance ??= new EventManager();
}
on(event: string, listener: EventCallback) {
;(this.#listeners[event]??= new Set()).add(listener);
if(this.#pending[event]){
this.#pending[event].forEach((args)=>listener(...args));
delete this.#pending[event];
}
}
emit(event: string, ...args: any[]) {
if (this.#listeners[event]) {
this.#listeners[event].forEach(cb=>cb(...args))
} else {
;(this.#pending[event]??=new Set()).add(args)
}
}
off(event: string, listener: EventCallback) {
this.#listeners[event]?.delete(listener);
}
once(event: string, listener: EventCallback) {
const wrapper = (...args: any[])=>{
listener(...args);
this.off(event, wrapper);
}
this.on(event, wrapper);
}
}
ES6小知识(??=)
逻辑运算符 ||= ??= &&= 都是一样的原理
const option = {}
function example(opts) {
//不存在则赋值
opts.foo ??= 'bar';
}
example(option)
//option {foo: 'bar'}
//等价于
//opts.foo = opts.foo ?? 'bar';
//opts.foo ?? (opts.foo = 'foo');