开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
你好,我是南一。这是我在准备面试八股文的笔记,如果有发现错误或者可完善的地方,还请指正,万分感谢🌹
一、简介
EventBus又叫事件总线,是发布-订阅设计模式的一种实现,用于线程或组件间的通信。今天要讲的是EventBus的实现,以及在React中组件通信的应用。
二、ES6实现
EventBus基础的四个方法,on订阅,off取消订阅,emit发布,once只订阅一次。
为了全局通用,对EventBus做了单例导出。
class EventBus {
static instance = null
static events = {}
constructor() {
if (!EventBus.instance) {
EventBus.instance = this
}
return EventBus.instance
}
on(type, callback) {
if (EventBus.events[type]) {
EventBus.events[type].push(callback)
} else {
EventBus.events[type] = [callback]
}
}
off(type, callback) {
if (!EventBus.events[type]) return console.log('不存在该事件');
if (!EventBus.events[type].includes(callback)) return console.log('该事件不存在此回调函数');
const index = EventBus.events[type].indexOf(callback);
EventBus.events[type].splice(index, 1)
}
emit(type, ...payload) {
if (!EventBus.events[type]) return console.log('不存在该事件');
EventBus.events[type].forEach(callback => callback(...payload))
}
once(type, callback) {
let cb = (...payload) => {
callback(...payload)
this.off(type, cb)
}
this.on(type, cb)
}
}
三、EventTarget实现
浏览器提供的EventTarget接口,其本身就带有注册事件,删除事件监听,派发的方法。再利用CustomEvent创建一个自定义的事件
class EventBus {
constructor() {
this.bus = document.createElement('fakeelement');
}
addEventListener = (eventType, callback) => {
this.bus.addEventListener(eventType, callback)
}
removeEventListener = (eventType, callback) => {
this.bus.removeEventListener(eventType, callback)
}
dispatchEvent = (eventType, detail = {}) => {
this.bus.dispatchEvent(new CustomEvent(eventType, { detail }));
}
}
四、观察者模式
观察者模式与发布订阅模式比较相似,两者的不同之处在于,观察者模式中被观察者与观察者知道对方的存在。发布订阅模式中,发布者与订阅者通过消息通道进行通信,无需知道对方的存在,解耦更彻底。
以下为观察者模式的代码实现,观察者可以主动申请加入观察队列,也可以被被观察者加入观察队列
// 被观察者
class Subject {
constructor() {
this.observerList = []
}
addObserver(observer) {
this.observerList.push(observer)
}
removeObserver(observer) {
const index = this.observerList.findIndex(o => o.name === observer.name);
this.observerList.splice(index, 1);
}
notifyObservers(message) {
const observers = this.observerList;
observers.forEach(observer => observer.notified(message));
}
}
// 观察者
class Observer {
constructor(name, subject) {
this.name = name;
subject && subject.addObserver(this);
}
notified(message) {
console.log(this.name, 'got message', message);
}
}
let subject = new Subject()
let observerA = new Observer('observerA', subject)
let observerB = new Observer('observerB')
subject.addObserver(observerB)
subject.notifyObservers('Hello')