为什么RxJS主题比多个事件监听器更快?

时间:2017-08-11 20:32:19

标签: javascript angular typescript rxjs dom-events

我最近发现,在其模板上多次使用的角度指令极大地阻碍了页面的性能。在下面的代码中找到了性能降低的原因:

@HostListener('window:keydown', ['$event'])
private keydown(e: KeyboardEvent) {
     this.doSomething(e);
}

我怀疑问题可能是由于在窗口keydown事件上注册多个事件侦听器引起的,因为每次在页面上重复该指令时都会注册一个新事件。为了测试该理论,我使用RxJS Subject创建了一个服务来处理该键盘事件:

@Injectable()
export class KeyboardService {
    constructor() {
        window.addEventListener('keydown', event => {
            this.keydownSubject.next(event);
        });
    }
}

private keydownSubject: Subject<KeyboardEvent> = new Subject<KeyboardEvent>();

get keydown(): Observable<KeyboardEvent> {
    return this.keydownSubject.asObservable();
}

然后我删除了指令中的@HostListener,并在ngOnInit中订阅了此服务的主题:

export class KeydownEventDirective implements OnInit, OnDestroy {
    constructor(private keyboardService: KeyboardService) {}

    private keydown(e: KeyboardEvent) {
        this.doSomething(e);
    }

    private keydownSubscription: Subscription;
    ngOnInit() {
        this.keydownSubscription =
            this.keyboardService.keydown.subscribe(e => {
                this.keydown(e);
            });
    }

    ngOnDestroy() {
        this.keydownSubscription.unsubscribe();
    }

    ...
}

解决方案加速了页面,我很难发现为什么会出现这种情况。为什么@HostListener或向窗口的keydown事件添加多个事件侦听器比对RxJS主题的​​多个订阅更不利于页面的性能?可能是默认情况下角度HostListeners不是被动侦听器吗?

2 个答案:

答案 0 :(得分:1)

它与主题无关,首先,注入服务是单例,因此将为所有指令提供一个实例,第二个在单例服务中,您在构造函数中注册单个方法来处理调用的keydown事件如果您在控制台中打印一条消息,您将看到一个电话。

但是使用Hostlistener by指令会有一个由标签注册的事件和在keydown事件上多次执行。

答案 1 :(得分:0)

您可能尝试在多个组件上捕获相同的事件,这将导致您执行所有订阅方法(private keydown(e: KeyboardEvent)),无论您是否按下了哪个键,因为您正在添加全局窗口级别的事件监听器。

与您在服务中所做的相比,它更好一些,尽管我很确定您也可以使用

public emitter: EventEmitter<any> = new EventEmitter<any>();

@HostListener('window:keydown', ['$event'])
private keydown(e: KeyboardEvent) {
     this.doSomething(e);
}

private doSomething(event: any): void {
     this.emitter.emit(event);
}

在您的服务中,然后公开EventEmitterSubject您的组件可以订阅并抓住keyDown事件。