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:
- A complex page means more bytes to download.
- Slower DOM access in JavaScript.
- 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
detach
ing andreattach
ing
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
orswitchMap
.
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 useisEqual
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
- Avoid an excessive DOM size
- to the rescue
- RxJS Patterns: Efficiency and Performance
- Angular Performance Checklist
- These 5 articles will make you an Angular Change Detection expert
- 3 Ways to Render Large Lists in Angular
- Increasing Performance - more than a pipe dream - Tanner Edwards - YouTube
- Help Angular to make your application faster
- Let Angular Manage Your RxJS Subscriptions Better
Top comments (0)