Performance Optimization
Esta página aún no está disponible en tu idioma.
Performance Metrics
Section titled “Performance Metrics”Before optimizing, understand these key metrics:
- Largest Contentful Paint (LCP) — When main content loads (target: < 2.5s)
- Bundle Size — Total JavaScript (target: < 100KB gzipped)
- Time to Interactive (TTI) — When app becomes interactive (target: < 3.5s)
Lazy Loading Modules and Routes
Section titled “Lazy Loading Modules and Routes”Lazy loading defers loading of feature modules until needed.
Before (Eager Loading)
Section titled “Before (Eager Loading)”// All modules loaded upfrontconst routes: Routes = [ { path: '', component: HomeComponent }, { path: 'user', component: UserComponent }, // ← Loaded immediately { path: 'admin', component: AdminComponent } // ← Loaded immediately];
// Bundle size: Large// Initial load time: SlowAfter (Lazy Loading)
Section titled “After (Lazy Loading)”const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'user', loadChildren: () => import('./features/user/user.module') .then(m => m.UserModule) }, { path: 'admin', loadChildren: () => import('./features/admin/admin.module') .then(m => m.AdminModule), canActivate: [AdminGuard] }];
// Bundle size: Smaller initial bundle// Initial load time: Faster// User modules loaded on demandCode Splitting
Section titled “Code Splitting”Break your application into smaller chunks:
// Route-based code splitting{ path: 'dashboard', loadComponent: () => import('./dashboard/dashboard.component') .then(m => m.DashboardComponent)}
// Feature-based code splitting{ path: 'reports', loadChildren: () => import('./features/reports/reports.module') .then(m => m.ReportsModule)}Change Detection Optimization
Section titled “Change Detection Optimization”Use OnPush Strategy
Section titled “Use OnPush Strategy”// ❌ Default - checks all components every time@Component({ selector: 'app-item', template: '<div>{{ item.name }}</div>'})export class ItemComponent { @Input() item: Item;}
// ✅ OnPush - only checks when input changes@Component({ selector: 'app-item', template: '<div>{{ item.name }}</div>', changeDetection: ChangeDetectionStrategy.OnPush // ← Add this})export class ItemComponent { @Input() item: Item;}Impact: 30-50% faster change detection in large apps
Avoid NgZone Performance Issues
Section titled “Avoid NgZone Performance Issues”// ❌ Every click triggers change detection@Component({ template: '<div (click)="expensiveOperation()">Click me</div>'})export class MyComponent { expensiveOperation() { // This runs change detection for (let i = 0; i < 1000000; i++) { // Heavy computation } }}
// ✅ Run outside Angular zone for non-visual operations@Component({ template: '<div (click)="handleClick()">Click me</div>'})export class MyComponent { private ngZone = inject(NgZone);
handleClick() { this.ngZone.runOutsideAngular(() => { for (let i = 0; i < 1000000; i++) { // Heavy computation - no change detection } });
// Update UI after computation this.ngZone.run(() => { // Update component state here }); }}Bundle Size Optimization
Section titled “Bundle Size Optimization”AOT Compilation (Default)
Section titled “AOT Compilation (Default)”# ✅ Production builds use AOT by defaultnpm run build
# Smaller bundle, faster rendering, catches template errors earlyPreload Strategy
Section titled “Preload Strategy”// Preload likely-needed modules while user interactsconst routes: Routes = [ { path: '', component: HomeComponent }, { path: 'dashboard', loadChildren: () => import('./dashboard/dashboard.module') .then(m => m.DashboardModule), data: { preload: true } // ← Preload this module }];
@Injectable({ providedIn: 'root' })export class PreloadAllModules implements PreloadingStrategy { preload(route: Route, load: Function): Observable<any> { if (route.data?.['preload']) { return load(); } return of(null); }}
// Use in RouterModuleRouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules})OnDemand Image Loading
Section titled “OnDemand Image Loading”<!-- ❌ Loads immediately --><img src="image.jpg" alt="Image">
<!-- ✅ Lazy loads when visible (native support) --><img src="image.jpg" alt="Image" loading="lazy">
<!-- ✅ Use smaller images on mobile --><picture> <source srcset="image-mobile.jpg" media="(max-width: 600px)"> <source srcset="image-desktop.jpg" media="(min-width: 601px)"> <img src="image-desktop.jpg" alt="Image" loading="lazy"></picture>Practical Example: Performance-Optimized List
Section titled “Practical Example: Performance-Optimized List”@Component({ selector: 'app-user-list', template: ` <div *ngFor="let user of users"> <app-user-card [user]="user"></app-user-card> </div> `})export class UserListComponent { users: User[] = [];
constructor(private userService: UserService) { this.userService.getUsers().subscribe(users => { this.users = users; }); }}
// Issues:// - No ChangeDetectionStrategy.OnPush// - No lazy loading// - No pagination for large lists// - No trackBy for *ngFor@Component({ selector: 'app-user-list', template: ` <div *ngFor="let user of users$ | async; trackBy: trackByUserId"> <app-user-card [user]="user"></app-user-card> </div> <button (click)="loadMore()">Load More</button> `, changeDetection: ChangeDetectionStrategy.OnPush})export class UserListComponent implements OnInit { private userService = inject(UserService); private destroyRef = inject(DestroyRef);
users$ = this.userService.getUsers().pipe( takeUntilDestroyed(this.destroyRef) );
ngOnInit() { // Pagination logic }
trackByUserId(index: number, user: User): string { return user.id; }
loadMore() { // Load additional users }}
// Optimizations:// ✅ ChangeDetectionStrategy.OnPush// ✅ async pipe (auto-unsubscribe)// ✅ trackBy for efficient list rendering// ✅ Pagination for large listsUnsubscribe from Observables
Section titled “Unsubscribe from Observables”// ❌ Memory leak - subscription never cleaned upexport class MyComponent implements OnInit { data: string[] = [];
constructor(private dataService: DataService) {}
ngOnInit() { this.dataService.getData().subscribe(data => { this.data = data; }); }}
// ✅ Properly unsubscribeexport class MyComponent implements OnInit, OnDestroy { data: string[] = []; private subscription: Subscription;
constructor(private dataService: DataService) {}
ngOnInit() { this.subscription = this.dataService.getData() .subscribe(data => { this.data = data; }); }
ngOnDestroy() { this.subscription.unsubscribe(); }}
// ✅ Best - use async pipe (auto-unsubscribe)export class MyComponent { data$ = this.dataService.getData();}trackBy for *ngFor
Section titled “trackBy for *ngFor”// ❌ Slow - recreates DOM elements on every change<div *ngFor="let item of items"> {{ item.name }}</div>
// ✅ Fast - reuses DOM elements<div *ngFor="let item of items; trackBy: trackByItemId"> {{ item.name }}</div>
// ComponenttrackByItemId(index: number, item: Item): string { return item.id;}Impact: 2-3x faster list rendering
Compression and Gzip
Section titled “Compression and Gzip”Enable Gzip compression for production:
# Check bundle sizenpm run build# Check dist/ folder size
# Gzip typically reduces size by 60-70%Performance Monitoring
Section titled “Performance Monitoring”// Log performance metricsif (performance.timing) { const perfData = performance.timing; const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart; console.log('Page Load Time: ' + pageLoadTime);}
// Modern API (recommended)const observer = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { console.log(`${entry.name}: ${entry.duration}ms`); }});
observer.observe({ entryTypes: ['navigation', 'paint'] });Performance Checklist
Section titled “Performance Checklist”- Lazy load feature modules
- Use
ChangeDetectionStrategy.OnPushon all components - Use
trackBywith*ngFor - Use
asyncpipe to auto-unsubscribe - Use virtual scrolling for large lists
- Remove unused dependencies
- Preload critical modules
- Enable Gzip compression in production
- Use AOT compilation (default)
- Monitor Core Web Vitals
Tools for Performance Analysis
Section titled “Tools for Performance Analysis”- Lighthouse — Chrome DevTools built-in (tab: Lighthouse)
- Angular DevTools — Browser extension for Angular apps
- Bundle Analyzer —
npm install -g webpack-bundle-analyzer - Web Vitals —
npm install web-vitals