手写发布订阅模式

196 阅读1分钟

发布订阅模式中,包含发布者,事件调度中心,订阅者三个角色。发布者和订阅者是松散耦合的,互不关心对方是否存在,他们关注的是事件本身。发布者借用事件调度中心提供的emit方法发布事件,而订阅者则通过on进行订阅。

实现思路

  1. 创建一个类(EventEmitter)
  2. 在该类上创建一个对象(时间调度中心),用来存储所有事件
  3. on 方法用来把函数 fn 都加到对象中(订阅者注册事件到调度中心)
  4. emit 方法取第一个参数当作事件 event,根据 event 值去执行对象中对应的函数(发布者发布事件到调度中心,调度中心处理代码)
  5. off 方法可以根据 event 值取消订阅(取消订阅)
  6. once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)
  7. 注册一个 newListener 用于监听新的事件订阅

完整代码

class EventEmitter {
    constructor () {
        this.event = {};
    }
    on (name, callback) {
        // 注册newListener监听新的事件订阅
        if (this.event[name] && name !== 'newEventLister') {
            this.emit('newEventLister', name);
        }
        // 一个事件可能有多次回调
        const callbacks = this.event[name] || [];
        callbacks.push(callback);
        this.event[name] = callbacks;
    }
    emit (name, ...args) {
        // 循环执行回调函数
        let callbacks = this.event[name] || [];
        callbacks.forEach(fn => {
            fn(...args);
        });
    }
    off (name, callback) {
        let callbacks = this.event[name] || [];
        // fn.initCallback !== callback 用于once的取消订阅
        this.event[name] = callbacks.filter(fn => fn !== callback && fn.initCallback !== callback);
    }
    once (name, callback) {
        // 在执行一次之后删除该函数
        let oneFn = (...arg) => {
            callback(...arg);
            this.off(name, callback);
        };
        oneFn.initCallback = callback;
        this.on(name, oneFn);
    }
}

const newEvent = new EventEmitter();
let fn = (a) => { console.log(a); };
newEvent.on('fn', fn);
newEvent.on('fn', (a) => { console.log(a + 1); });
newEvent.emit('fn', '1');
newEvent.emit('fn', '2');
newEvent.off('fn', fn);
newEvent.emit('fn', '第三次');
newEvent.once('once', (a, b) => {
    console.log(a + b);
});
newEvent.emit('once', 'name:', 'li');