After investigating a page's slow performance, I identified an angular directive as the root cause. The culprit was a piece of code that registered event listeners on the window keydown event multiple times:
@HostListener('window:keydown', ['$event'])
private keydown(e: KeyboardEvent) {
this.doSomething(e);
}
To address this issue, I decided to create a service utilizing an RxJS Subject to handle the keyboard event more efficiently:
@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();
}
By removing the @HostListener
from the directive and subscribing to the service's subject in ngOnInit, I was able to significantly improve the page's speed:
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();
}
...
}
This solution raised questions about why @HostListener
or multiple event listeners were impacting performance more than multiple subscriptions to an RxJS Subject. Could it be that angular HostListeners are not passive listeners by default?