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

802 阅读2分钟

根据消息发送者过滤监听消息存在问题

一个事件触发的时候,因为多次监听,而需要走多个filter

例子:如果我执行两次onlyOnHelloForxx

    const listener1 = onlyOnHelloForxx(handler1);
    const listener2 = onlyOnHelloForxx(handler2);

则当一个事件来的时候,会这样走:

event-filter
但我们并不希望,一个事件触发的时候,因为多次监听,而需要走多个filter。只希望被走一次,像这样的结构:
event-filter-correct

因此,我们可以改造下filter:

在这之前,别急,我们先看看,原先流程。

    export interface Event<T> {
	(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;
    }
    export namespace Event {
        export function fromNodeEventEmitter<T>(emitter: NodeEventEmitter, eventName: string, map: (i: I) => O) => T = id => id): Event<T> {
            const fn = (...args: any[]) => result.fire(map(...args)); 
            const onFirstListenerAdd = () => emitter.on(eventName, fn); 
            const onLastListenerRemove = () => emitter.removeListener(eventName, fn);
            const result = new Emitter<T>({ onFirstListenerAdd, onLastListenerRemove });
            return result.event;
        }
        export function filter<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
            return (listener, thisArgs = null, disposables?) => 
                event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
        }
    }

    // demo -- start
    const onHello = Event.fromNodeEventEmitter<Electron.WebContents>(ipcMain, 'ipc:hello', ({sender}) => sender);
    const onlyOnHelloForxx = Event.filter(onHello, (sender: any) => sender == 'xx');

    const listener1 = onlyOnHelloForxx(handler1);
    const listener2 = onlyOnHelloForxx(handler2);
    // demo -- end

    // 触发事件
    webcontents.send('ipc:hello', {d: 1});
    

运行流程:

     webcontents.send('ipc:hello', {d: 1});
  => emitter.on(eventName, fn)
  => fn
  => result.fire
  => 所有使用r`result.event==onHello==filter==onlyOnHelloForxx`注册的回调都被执行

因此,我们使用n次onlyOnHelloForxx,则会执行n次filter(e),即: 一个事件,过滤执行n次, 执行n个监听

而我们将Event.filter改造后,增加snapshotfilter(e)就只被执行一次。

export namespace Event {
	export function filter<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
        return snapshot((listener, thisArgs = null, disposables?) => 
            event(e => filter(e) && listener.call(thisArgs, e), null, disposables));
    }

    export function snapshot<T>(event: Event<T>): Event<T> {
		let listener: IDisposable;
		const emitter = new Emitter<T>({
			onFirstListenerAdd() {
				listener = event(emitter.fire, emitter);
			},
			onLastListenerRemove() {
				listener.dispose();
			}
        });
		return emitter.event;
	}
}

   // demo -- start
    const onHello = Event.fromNodeEventEmitter<Electron.WebContents>(ipcMain, 'ipc:hello', ({sender}) => sender);
    const onlyOnHelloForxx = Event.filter(onHello, (sender: any) => sender == 'xx');

    const listener1 = onlyOnHelloForxx(handler1);
    const listener2 = onlyOnHelloForxx(handler2);
    // demo -- end

    // 触发事件
    webcontents.send('ipc:hello', {d: 1});

运行流程:

     webcontents.send('ipc:hello', {d: 1});
  => emitter.on(eventName, fn)
  => fn
  => result.fire
  => 所有使用`result.event==onHello==filter`注册的回调都被执行, 
  => 上述内容只被注册了一次,是在`snapshot``onFirstListenerAdd`所注册, 因此只执行一次`filter(e)`。
        onFirstListenerAdd() {
                listener = event(emitter.fire, emitter);
            }
  => 执行`emitter.fire`
  => 所有使用`emitter.event==onlyOnHelloForxx`注册的被执行。

因此,我们使用n次onlyOnHelloForxx,则会执行n次监听,但filter在一个事件来的时候,只执行一次。从而实现了:一个事件,过滤执行一次, 执行n个监听