前端手写简单的发布-订阅模式

79 阅读2分钟

在秋招刚开始的时候,我信心十足的投递了字节的前端岗位,也不出意料约到了面试,因为是秋招第一个面试,也不了解字节还有面评这个说法,第一次就失败了,还脏了面评😭,当时让我手写的就是发布订阅模式,没有写出来,今天突然想起,就在写一下吧。

我会以小白的视角尽可能写的详细一点,该发布订阅模式包含三个功能,分别是订阅事件(subscribe),取消订阅事件(unSubscribe)和发布事件(dispatch),希望有误的地方大家可以指出。

// 定义一个class类
class EventCenter {
    // 定义事件容器,用来装事件数组
    constructor () {
        this.events = {}
    }
    
    // 订阅事件
    subscribe (eventsName, callback) {
        // 判断当前容器是否有这个事件
        if (!this.events[eventName]) {
            // 如果没有的话,创建这个事件的容器
            this.events[eventName] = []
        }
        // 如果有的话,在这个容器中存放事件callback
        this.events[eventName].push(callback)
    }
    
    // 取消订阅事件
    unSubscribe (eventName, callback) {
        // 先判断是否有这个事件
        if (!this.events[eventName]) {
            // 没有的话抛出error
            return new Error('do not have this event')
        }
        
        // 有事件的话,判断是否有事件callback
        if (!callback) {
            // 没有事件callback的话,直接移除这个事件
            delete this.events[eventName]
        } else {
            // 有事件callback的话,找到其索引,未找到其索引的话返回 -1
            const index = this.events[eventName].findIndex((el) => el === callback)
            
            // 判断是否有这个索引
            if (index === -1) {
                // 未找到索引,抛出error
                return new Error('do not have this event callback')
            }
            
            // 找到其索引,移除这个事件的callback
            this.events[eventName].splice(index, 1)
            
            // 移除之后判断事件容器是否为0,如果为0,就代表没有任何订阅者了,删除该事件
            if(this.events.length === 0) {
                delete this.events[eventName]
            }
        }
    }
    
    // 触发事件
    dispatch(eventName, ...args) {
        // 判断是否有这个事件,没有的话抛出错误
        if (!this.events[eventName]) {
            return new Error('do not have this event')
        }
        
        // 如果有的话,触发该事件
        this.events[eventName].forEach((el) => {
            el(...args)
        })
    }

}


// 测试该发布订阅模式
// 创建一个实例
const eventCase = new EventCenter()

// 给这个事件订阅一个事件
eventCase.subscribe('click', (x, y) => {
    console.log(x, y)
})

// 触发该事件
eventCase.dispatch('click', 111, 222)  // 111, 222