简单手写发布订阅

270 阅读2分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

导言

其实不难写,只要理解了它的三个核心:订阅列表,订阅,发布。三个概念就能很容易写出来。

实现

1. 思路

其实可以把发布订阅当做买卖房子来看:

  • 订阅列表:购房者
  • 订阅:订房者
  • 发布:通知部

大概执行过程就是:订阅 -> 加入订阅列表 -> 通知

张三来订房,订好房后加入订阅列表,等有房时通知部会去通知他。

实现思路:维护一个数组类型的订阅列表,在添加两个订阅和发布方法,每次通过订阅者将订阅方法加入订阅列表中,而后通过发布方法通知订阅者。

2. 实现

const issue = {
    // 订阅者队列
    queue: [],

    // 订阅
    subscribe(type, func){
        // 判断此类型在订阅列表中是否不存在
        if(this.queue[type] == undefined){
            // 如果不存在则将它以数组形式加入订阅列表中
            this.queue[type] = []
        }
        // 将这个类型的方法加入当前类型中
        this.queue[type].push(func)
    },

    // 发布
    notification(type){
        // 判断此类是否不存在
        if(this.queue[type] == undefined){
            throw '类型不存在'
        }
        // 遍历取出这个类型下的所有任务
        for(let i = 0; i < this.queue[type].length; i++ ){
            // 拿到这个类型下的每个任务
            let funcs = this.queue[type][i]
            // 判断有无带参数
            if(arguments[1]){
                // 存放参数
                const args = []
                // 拿到调用函数时的传值,声明 i 为 1,表示从第二个值开始拿
                // 诺不然它会将第一个代表函数类型的值也拿到
                for(let i = 1; i < arguments.length; i++){
                    // 这里对应数组中的位置减一,如果不减一,那么会直接在数组的第二位开始插入
                    // 这样会导致数组的第一项是个空值,且函数使用这个参数集会报 undefined 错误
                    args[i-1] = arguments[i]
                }
                // 调用执行并使用扩展运算符将 args 传进去
                funcs(...args)
            }else{
                // 无参直接调用
                funcs()
            }
        }
    }
}

\