I recently discovered that the performance of a page was greatly hindered by an angular directive which was used multiple times on its template. The cause of the slower performance was found in the following bit of code:
@HostListener('window:keydown', ['$event'])
private keydown(e: KeyboardEvent) {
this.doSomething(e);
}
I suspected the problem might have been caused by the registration of multiple event listeners on the window keydown event, because a new one was registered each time that directive was repeated on the page. To test that theory, I created a service with an RxJS Subject to handle that keyboard event:
@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();
}
I then removed the @HostListener in the directive, and subscribed to this service's subject in 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();
}
...
}
The solution sped up the page, and I have had difficulty discovering why this would be the case. Why would @HostListener or adding multiple event listeners to the window's keydown event be more detrimental to the page's performance than multiple subscriptions to an RxJS Subject? Could it be that angular HostListeners are not passive listeners by default?