OnPush стратегия обнаружения изменений — мощный инструмент для оптимизации Angular приложений. Рассмотрим ключевые техники максимального повышения производительности.
Стратегия OnPush работает по следующим правилам:
@Input
)markForCheck()
// Плохо - мутация объекта
this.user.name = 'New Name';
// Хорошо - создание нового объекта
this.user = {...this.user, name: 'New Name'};
Почему важно: OnPush проверяет ссылки, а не содержимое объектов.
// В компоненте
data$ = this.service.data$;
// В шаблоне
{{ data$ | async }}
Преимущества:
markForCheck()
@Pipe({
name: 'fullName',
pure: true // true по умолчанию
})
export class FullNamePipe implements PipeTransform {
transform(user: User): string {
return `${user.firstName} ${user.lastName}`;
}
}
Важно: Pure pipes кэшируют результаты при тех же входных параметрах.
// В компоненте
trackByFn(index: number, item: Item): number {
return item.id; // Уникальный идентификатор
}
// В шаблоне
<div *ngFor="let item of items; trackBy: trackByFn">
Эффект: Angular будет перерисовывать только измененные элементы.
const routes: Routes = [
{
path: 'feature',
loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule)
}
];
Результат: Загружаются только необходимые компоненты.
constructor(private cdr: ChangeDetectorRef) {}
updateData() {
this.dataService.getData().subscribe(data => {
this.data = data;
this.cdr.markForCheck(); // Явно помечаем для проверки
});
}
platformBrowser()
.bootstrapModule(AppModule, {ngZone: 'noop'});
Когда использовать: Для максимальной производительности в сложных приложениях.
@Component({
selector: 'app-data-provider',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DataProviderComponent {
@Input() data: any;
}
Применение: Для изоляции тяжелых вычислений.
Мутация данных:
// Плохо
this.items.push(newItem);
// Хорошо
this.items = [...this.items, newItem];
Сложные вычисления в шаблоне:
<!-- Плохо -->
{{ calculateComplexValue() }}
<!-- Лучше -->
{{ preCalculatedValue }}
Избыточные проверки:
// Избегайте лишних detectChanges()
this.cdr.detectChanges();
Angular DevTools:
Chrome Performance Tab:
Оптимизация с OnPush:
Пример идеального компонента:
@Component({
selector: 'app-optimized',
template: `
<div *ngFor="let item of items$ | async; trackBy: trackByFn">
{{ item.name | uppercase }}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class OptimizedComponent {
items$ = this.service.getItems();
trackByFn = (index: number, item: Item) => item.id;
constructor(private service: DataService) {}
}
Итоговый результат: При правильном применении OnPush можно добиться 2-10x улучшения производительности в крупных приложениях.