发布订阅模式是一个前端开发中非常常用的模式。下面是某大厂一道常见的面试真题,题目真心不难,但要几分钟内快速写出来,却也并不容易。
工作中,有些东西我们从来没有接触过、见闻过,这个时候不OK,是正常的。但更多的情况是,很多的东西不是我们真的就搞不懂,弄不明白,而往往是看过、知道、了解、用过一两次,却因为缺乏反复的刻意练习,从而达不到熟练的程度,做不到运用自如,又或者因为缺乏及时的总结记录,从而时间一长关键收获都已被遗忘或者即使有总结记录也是一点,未能组成体系,从而不OK,这是令人扼腕叹息的。
长此以往,我们似乎知道很多,却似乎又什么也不知道,这是一种非常尴尬又令人痛心的状态。解决办法也似乎不多,就是刻意练习、及时记录总结、找其他人帮助审视和梳理散点串联成体系。
下面,我们就开始写起来吧~
一、实现发布订阅模式
/**
* 使用JS实现发布订阅模式
*/
type Handler = (params: unknown) => void;
interface Handlers {
[prop: string]: Array<Handler|null>;
}
export class Event {
handlers: Handlers = {};
on(type: string, handler: Handler) {
if (!this.handlers[type]) {
this.handlers[type] = [];
}
this.handlers[type].push(handler);
}
off(type: string, handler: Handler) {
if (!handler) {
delete this.handlers[type];
return;
}
if (!this.handlers[type]) {
throw new Error('未绑定该事件');
}
const idx = this.handlers[type].indexOf(handler);
if (idx === -1) {
throw new Error('未绑定该处理函数');
}
this.handlers[type].splice(idx, 1);
if (!this.handlers[type].length) {
delete this.handlers[type];
}
}
emit(type: string, ...params: unknown[]) {
if (!this.handlers[type] || !this.handlers[type].length) {
return;
}
this.handlers[type].forEach((handler) => {
handler && handler(params);
});
}
}
// const eventBus = new Event();
// const b = (params: unknown) => {
// console.log('B recieved', params);
// };
// const c = (params: unknown) => {
// console.log('C recieved', params);
// };
// eventBus.on('publish', b);
// eventBus.on('publish', c);
// eventBus.emit('publish', 'message 1');
// eventBus.off('publish', b);
// eventBus.off('publish', c);
// eventBus.emit('publish', 'message 2');
二、实现观察者模式
/**
* 使用JS/TS实现观察者模式
* 例如,a为发布者, b、c为观察者
*/
export class Subject {
observers: Observer[] = [];
add(observer: Observer) {
this.observers.push(observer);
}
remove(observer: Observer) {
const idx = this.observers.indexOf(observer);
if (idx === -1) {
throw new Error('没有该observer');
}
this.observers.splice(idx, 1);
}
notify() {
this.observers.forEach((observer) => {
observer.update();
});
}
}
export class Observer {
name: string = '';
constructor(name: string) {
this.name = name;
}
update() {
console.log(`${this.name} received`);
}
}
// const a = new Subject();
// const b = new Observer('B');
// const c = new Observer('C');
// a.add(b);
// a.add(c);
// a.notify();
// a.remove(b);
// a.remove(c);
// a.notify();
代码见这里。