loading...

Every Performance tips for angular app (RunTime Part)

imm9o profile image Islam Muhammad ・4 min read

This is the second part of Every Performance tips for the angular app, in this post my primary focus here to list every performance tips about runtime and what to avoid or optimize.

Avoid render large DOM Tree in views

The Problem

A large DOM tree can slow down your page performance in multiple ways:

  1. A complex page means more bytes to download.
  2. Slower DOM access in JavaScript.
  3. Memory performance when select genral selectors like li.

How to enhance ?

  • Use <ng-container> The Angular is a grouping element that doesn't interfere with styles or layout because Angular doesn't put it in the DOM.
  • Use Virtual Scrolling, Infinite scroll or Pagination techniques to avoid render large list at once.
  • Always use trackBy to decrease the number of DOM mutations as you know Manipulating the DOM is an expensive task.

Optimize template expressions

The Problem

Angular executes template expressions after every change detection cycle.

How to enhance ?

  • Expressions should finish quickly avoid complex expressions.
  • Avoid Function Calls and Getters in Views instead use a custom pure pipe.
  • Consider caching values by using pure pipes.

Avoid unnecessary Change Detection (CD)

The Problem

On each asynchronous event, Angular performs change detection over the entire component tree. Although the code which detects for changes is optimized for inline-caching, this still can be a heavy computation in complex applications.

How to enhance?

  • OnPush Change detection stratgy

Unlike the default strategy, which checks a component whenever there’s a change in your app, OnPush change detection reacts only to changes in the @input parameters, or when you manually trigger detection.

@Component({
  ...,
  changeDetection: ChangeDetectionStrategy.OnPush
})
  • Use detaching and reattaching

When we use deatch the CD Angular will not perform check for the entire component subtree until it is reattached.

export class AComponent {
  constructor(public cd: ChangeDetectorRef) {
    this.cd.detach();
  }
}
  • Run outside angular

In some cases we want to execute async call without running CD in angular as ui will not be changed, so there is a function called runOutsideAngular we can use to run any async function outside angular CD.

export class AComponent implements OnDestroy {
  interval = null;
  constructor(private _zone: NgZone) {
    this._zone.runOutsideAngular(() => {
      this.interval = window.setInterval(() => {
        console.log(`Triggers OutsideAngular`);
      }, 10);
    });
  }

  ngOnDestroy() {
    if (this.interval) {
      clearInterval(this.interval);
    }
  }
}

Optimize subscription in Component and Views

The Problem

Subscribe to one or more observable can lead to a memory leak as the observable stream is left open.

How to enhance ?

  • Avoid subscribing to observables from components and instead subscribe to the observables from the template by using Async pipe.
  • If you have to subscribe from components consider unsubscribe inside ngOnDestroy lifecycle hooks function.
  • Avoid multi async pipe in Views.
  • Consider using canceling operators like takeUntil, takeWhile or switchMap.

Avoid unnecessary emitting inside observable

The Problem

Emitting the same value multiple times or emitting unused value inside observable can lead to unnecessary change detection in angular.

How to enhance ?

  • Use filter: Filter items emitted by the source Observable by only emitting those that satisfy a specified predicate.
  • Use throttleTime: Emits a value from the source Observable, then ignores subsequent source values for duration milliseconds, then repeats this process.
  • Use debounceTime: Emits a value from the source Observable only after a particular time span has passed without another source emission.
  • Use auditTime: Ignores source values for duration milliseconds, then emits the most recent value from the source Observable, then repeats this process.
  • Use distinctUntilChanged: with primitive data and consider use isEqual function from lodash for none-primitive data like array and object.
import * as isEqual from 'lodash.isequal';
import { distinctUntilChanged } from 'rxjs/operators';

export class AComponent {
  constructor() {}

  get observable$() {
    return this.observable.pipe(distinctUntilChanged(isEqual));
  }
}

Resources

Posted on Mar 15 '19 by:

imm9o profile

Islam Muhammad

@imm9o

Discovery πŸ” requires experimentation βš— and this experiment will take time πŸ•.

Discussion

markdown guide