Performance Optimization
Performance Optimization
Change Detection Strategies
By default, Angular checks every component in the entire tree whenever anything changes. For large apps, this gets expensive. OnPush tells Angular only to check a component when its @Input() references change, an event fires inside it, or an Observable it's subscribed to emits.
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
import { Course } from './course.model';
@Component({
selector: 'app-course-card',
templateUrl: './course-card.component.html',
changeDetection: ChangeDetectionStrategy.OnPush // only check when inputs change
})
export class CourseCardComponent {
@Input() course!: Course;
}
When using OnPush, always pass new object references instead of mutating existing ones. Angular compares by reference, not by value.
// Wrong — Angular won't detect this change
this.course.name = 'New Name';
// Correct — create a new object so the reference changes
this.course = { ...this.course, name: 'New Name' };
Lazy Loading and Code Splitting
You already saw basic lazy loading at the intermediate level. At the advanced level, you combine it with preloading strategies so critical routes are preloaded in the background after the initial page loads.
// app-routing.module.ts
import { PreloadAllModules } from '@angular/router';
@NgModule({
imports: [
RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules // preload lazy modules in the background
})
]
})
export class AppRoutingModule {}
Writing a custom preloading strategy — only preload routes you flag explicitly:
// selective-preload.strategy.ts
import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class SelectivePreloadStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
return route.data?.['preload'] ? load() : of(null);
}
}
// Mark specific routes to preload
{ path: 'courses', loadChildren: () => import('./courses/courses.module').then(m => m.CoursesModule),
data: { preload: true } }
trackBy in ngFor
By default, *ngFor re-renders the entire list every time the array changes. trackBy tells Angular which item is which, so it only re-renders items that actually changed.
// component
trackByCourseId(index: number, course: Course): number {
return course.id;
}
<li *ngFor="let course of courses; trackBy: trackByCourseId">
{{ course.name }}
</li>
For large lists, this makes a significant difference in rendering performance.











