根据消息发送者过滤监听消息存在问题
一个事件触发的时候,因为多次监听,而需要走多个filter
例子:如果我执行两次onlyOnHelloForxx
,
const listener1 = onlyOnHelloForxx(handler1);
const listener2 = onlyOnHelloForxx(handler2);
则当一个事件来的时候,会这样走:
但我们并不希望,一个事件触发的时候,因为多次监听,而需要走多个filter
。只希望被走一次,像这样的结构:
因此,我们可以改造下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
改造后,增加snapshot
,filter(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个监听