EventEmitter

22 5月

仿照events实现个发布订阅模式的EventEmitter。

addListener注册event,保存进map。只注册一个event时,回调函数作为function型对象直接存进map。注册多个同名event时,回调函数作为Array型存进map。

removeListener撤销从map中撤销已注册的event。如果只注册了一次,直接从map中删除。如果注册了多次,从回调函数的Array中删除相应的回调函数。

emit触发event。

class EventEmitter {
    constructor() {
        this._events = this._events || new Map();
    }

    emit(type, ...args) {
        let handler = this._events.get(type);   // 从 this._events 中获取事件的回调函数

        if (Array.isArray(handler)) {           // 数组表示有多个listener,需要依次触发回调函数
            for (let i = 0; i < handler.length; i++) {
                if (args.length > 0) {
                    handler[i].apply(this, args);
                } else {
                    handler[i].call(this);
                }
            }
        } else {
            if (args.length > 0) {
                handler.apply(this, args);
            } else {
                handler.call(this);
            }
        }

        return true;
    };

    addListener(type, fn) {
        const handler = this._events.get(type);

        if (!handler) {
            // 将事件与回调函数保存到 this._events
            this._events.set(type, fn);
        } else if (typeof handler === 'function') {
            // 如果 handler 是函数,说明目前只有一个监听者,现在要让 handler 变成数组
            this._events.set(type, [handler, fn]);
        } else if (Array.isArray(handler)) {
            // 如果 handler 是数组,说明已经有多个监听者,只要简单 push 进数组即可
            handler.push(fn);
        }
    }

    removeListener(type, fn) {
        const handler = this._events.get(type);

        if (!handler) {
            return null;
        } else if (typeof handler === 'function') {
            // 如果 handler 是函数,说明目前只有一个监听者,直接删除
            this._events.delete(type, fn);
        } else if (Array.isArray(handler)) {
            // 如果 handler 是数组,说明已经有多个监听者,移除相应的监听者
            let position = -1;
            handler.forEach((item, index) => {
                if (item === fn) {
                    position = index;
                }
            });

            if (position === -1) {
                return null;
            }

            handler.splice(position, 1);
            // 如果清除后,数组内只有一个函数,那就取消数组,以函数形式保存
            if (handler.length === 1) {
                this._events.set(type, handler[0]);
            }
        }
    }
}

module.exports = EventEmitter;

测试:

const EventEmitter = require( './eventEmitter.js');

const emitter = new EventEmitter();

function callback1(name) {
    console.log(`I am ${name}`);
}
function callback2(name) {
    console.log(`${name} is fool`);
}
function callback3(name) {
    console.log(`${name} is clever`);
}

emitter.addListener('person', callback1);
emitter.addListener('person', callback2);
emitter.addListener('person', callback3);
emitter.removeListener('person', callback2);

emitter.emit('person', 'icon man');

太粗糙了,参数也没校验,异常也没处理,once/removeAllListeners也没实现。

发表评论

电子邮件地址不会被公开。 必填项已用*标注