前端(Electron)事件系统设计第二章

1,700 阅读3分钟

实现自己想要的Emitter

对于注册事件这个过程,我们分别想在以下节点做一些事情:

  • 第一次有注册监听的时
  • 第一次监听注册成功时
  • 当有监听被注册时
  • 所有监听移除时

同时我们需要它具有如下能力:

  • 一次性移除所有监听(而不是我们自己一个一个removeEventListener
  • 移除单个listener

因此,我们设计了如下结构:

    export interface EmitterOptions {
        onFirstListenerAdd?: Function; // 第一次注册监听回调
        onFirstListenerDidAdd?: Function; // 低一次注册监听完成回调
        onListenerDidAdd?: Function; // 当有事件被监听成功
        onLastListenerRemove?: Function; // 当最后一个事件被移除
    }
    export class Emitter<T> {
        private readonly _options?: EmitterOptions; // 事件触发器选项,在事件添加监听和移除时候,相关节点,暴露出来,比如:第一个监听被添加、最后一个监听被移除。
        private _disposed: boolean = false; // 此事件桥是否已经释放
        private _event?: Event<T>; // 返回一个事件注册函数
        protected _listeners?: LinkedList<Listener<T>>; // 事件监听
        constructor(options?: EmitterOptions) {
            this._options = options;
        }
         // 获取“emitter.on”函数
        get event(): Event<T> {
            ...
        }
        // 相当于:emitter.emit
        fire(event: T): void {
             ...
        }

        // 解除所有监听
        dispose() {
            ...
        }

    }

首先,关于event(on函数)的实现如下(详细的函数会放最下面,有需要的看下即可):

    get event(): Event<T> {
        // 相当于emitter.on
        if (!this._event) {
            // 不存在"on"函数,则创建一个并返回
            this._event = (listener: (e: T) => any, thisArgs?: any) => {
                this.initListeners(); // 初始化listeners 集合
                const firstListener = this._listeners.isEmpty();
                this.onFirstListenerAdd();// 当第一个listener被添加的时候,执行回调。
                const remove = this._listeners.push(!thisArgs ? listener : [listener, thisArgs]); // 加入listener,并且返回一个删除改listener的函数。
                this.onFirstListenerDidAdd();// 第一个listener被添加完成,执行回调
                this.onListenerDidAdd();// 当有listener被添加,执行回调
                return this.eventDispose(remove); // 返回解除此事件的函数
            }
        }
        return this._event;
    }

其次,关于fire(emit函数)函数的实现如下:

    fire(event: T): void {
        if (this._listeners) {
            while (this._listeners.size > 0) {
                const listener = this._listeners.shift()!;
                try {
                    if (typeof listener === 'function') {
                        listener.call(undefined, event);
                    } else {
                        listener[0].call(listener[1], event);
                    }
                } catch (e) {
                    console.log(e);
                }
            }
        }
    }

最后,关于dispose函数实现:

    dispose() {
        if (this._listeners) {
            this._listeners.clear();
        }
        this._disposed = true;
        this.onLastListenerRemove();
    }

至此,我们实现了一个自己的Emitter, 我们来使用看看:

    const emitter = new Emitter({
        onFirstListenerAdd: () => console.log('onFirstListenerAdd');
        onFirstListenerDidAdd: () => console.log('onFirstListenerDidAdd');
        onListenerDidAdd: () => console.log('onListenerDidAdd');
        onLastListenerRemove: () => console.log('onLastListenerRemove');
    });
    const listener1 = emitter.event(() => console.log('这是我们的自己的监听回调-1')); // fire时候,则会执行回调
    const listener2 = emitter.event(() => console.log('这是我们的自己的监听回调-2')); // fire时候,则会执行回调
    listener1.dispose(); // 移除监听1
    // emitter.dispoase(); 移除所有监听
    emitter.fire(); // 触发事件

ps: 上述过程中使用到的一些具体实现:

    private initListeners() {
        if (!this._listeners) {
            this._listeners = new LinkedList();
        }
    }

    private onFirstListenerAdd(firstListener: Listener) {
        if (firstListener && this._options && this._options.onFirstListenerAdd) {
            this._options.onFirstListenerAdd(this);
        }
    }

    private onFirstListenerDidAdd(listener: Listener) {
        if (firstListener && this._options && this._options.onFirstListenerDidAdd) {
            this._options.onFirstListenerDidAdd(this);
        }
    }

    private onListenerDidAdd(listener: Listener) {
        if (this._options && this._options.onListenerDidAdd) {
            this._options.onListenerDidAdd(this, listener, thisArgs);
        }
    }

    private onLastListenerRemove() {
        if (this._options && this._options.onLastListenerRemove) {
            const hasListeners = (this._listeners && !this._listeners.isEmpty());
            if (!hasListeners) {
                this._options.onLastListenerRemove(this);
            }
        }
    }

    private eventDispose(remove: function) {
        return {
            dispose: () => {
                if (!this._disposed) {
                    remove();
                    this.onLastListenerRemove();
                }
            }
        }
    }

这个emitter有啥用呢,请听下回分解:如何给ipcMain赋予我们自己实现的Emitter的能力