Building Performance First Angular Apps - Part 2
If you liked my tips on Angular Performance in HTML templates, this week we can dig in some more tips.
This time, we're looking at how to fine tune the architecture to get the most out of Angular in terms of performance.
Unsubscribe observables
export class AppComponent implements OnInit, OnDestroy {
users = [];
subs = new Subscription();
constructor(private userService: UserService){ }
ngOnInit() {
this.subs.add(
this.userService.users$.subscribe(newUsers => this.users = newUsers) );}
ngOnDestroy() {
this.subs.unsubscribe();
}}
Avoid sending heavily updated objects through input
In the example below, we're sending the users array through @Input. But to receive updates to the array, we need to implement ngOnChanges which is also triggered for any other input change.
Instead, you can use Observables to notify when the array has changed and send the new value.
<app-hello [users]="users"></app-hello>
--------------------------------------------------
export class HelloComponent implements OnChanges {
@Input() users: string;D
ngOnChanges(changes: SimpleChanges) {
this.users = changes.users.currentValue;
}
}
Use debounce and switchMap to avoid unnecessary requests
In the code below, we're delaying/debouncing the request with 500ms and using switchMap to cancel any pending request but the latest one. Check out the working code here.
this.searchText$.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(movName => this.searchService.search(movName))
);
Use Lazy Loading
const routes: Routes = [{
path: 'items',
loadChildren: () => import('./items/items.module')
.then(m => m.ItemsModule)
}];
Lazy Loading for Modules (as seen above) - click here to read more
Lazy Loading for Components - click here to read more
Make use of Singleton Services
Singleton Services come by default in Angular, and having one instance in the whole app can benefit in some cases. You can cache some data or have subjects to which other components subscribe. Read more on Singleton Services
export class SearchService {
private cachedData = [];
constructor(private http$: HttpClient) {}
…
}
Fetch data at the highest level available
When the same piece of data is needed in multiple components, you can fetch it at a higher level (a service) and send the updates through a Subject.
Adjust Change Detection
Angular is eager to run the change detection on each change in the application. However this might not be the best approach performance-wise.
You can look into switching the Change Detection Strategy to On-Push. With On-Push, Angular will trigger change detection on component inputs, events from the component or its children, by using async pipe or by triggering change detection explicitly. You'll also have to refrain from mutating objects directly.
A great example is explained on Angular University.
Use Ivy
Make use of the new Ivy engine. Enabled by default in Angular 9+.
Read more here
Speed up Unit Tests
If you're using Ivy, you're set, the Ivy engine comes with caching for TestBed components.
However, if you're stuck with an older version of Angular, take a look at ng-bullet.
These tips & tricks don't represent an exhaustive list, and other improvements are definitely out there. Let's chat on Twitter about these & other tips on Angular performance.