Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HostListener slowing down application: Angular2

Tags:

angular

I have a hostListner listening to the scroll event in my Angular2 application. I'm using it to check if the user scrolls at the bottom of the page and execute a method when the user reaches the bottom of the page. I have constructed the hostlistner in the following way:

  @HostListener('window:scroll', [])
  onWindowScroll() {
   const scrolledPercent = /* some logic to calculate the percentage scrolled */
  if ( condition1 && condition2 .... )
    { 
     // doing something here
    }
  }

But this is slowing down my application, not in a very significant way but the scrolling on the page is not smooth anymore. Maybe because the hostlistner is constantly looking for the page to scroll, so that subscription is making the whole scrolling experience laggy. I tried by removing the hostListner and the scroll was smooth again. Has anybody noticed this behavior? If not, what is the best way to subscribe to the scroll event on a page using Angular2?

like image 819
Aiguo Avatar asked Jul 21 '17 01:07

Aiguo


1 Answers

You can run this function outside angular zone to prevent redundant change detection cycles.

For that i would override EventManager to keep listener outside zone.

custom-event-manager.ts

import { Injectable, Inject, NgZone  } from '@angular/core';
import { EVENT_MANAGER_PLUGINS, EventManager } from '@angular/platform-browser';

@Injectable()
export class CustomEventManager extends EventManager {
  constructor(@Inject(EVENT_MANAGER_PLUGINS) plugins: any[], private zone: NgZone) {
    super(plugins, zone); 
  }    

  addGlobalEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
    if(eventName.endsWith('out-zone')) {
      eventName = eventName.split('.')[0];
      return this.zone.runOutsideAngular(() => 
          super.addGlobalEventListener(element, eventName, handler));
    } 

    return super.addGlobalEventListener(element, eventName, handler);
  }
}

app.module.ts

  ...
  providers: [
    { provide: EventManager, useClass: CustomEventManager }
  ]
})
export class AppModule {}

And update view only by calling changeDetector.detectChanges

@HostListener('window:scroll.out-zone', []) // notice out-zone
onWindowScroll() {
  const scrolledPercent = /* some logic to calculate the percentage scrolled   */
  if ( condition1 && condition2 .... ) { 
      this.cd.detectChanges();
  }
}

Plunker Example

See also

  • Angular 2 how to keep event from triggering digest loop?
like image 189
yurzui Avatar answered Oct 31 '22 14:10

yurzui