Как оптимизировать производительность Angular-приложения?
Оптимизация производительности Angular-приложения включает множество аспектов: от работы Change Detection до ленивой загрузки модулей и оптимизации рендеринга DOM. Angular предоставляет богатый инструментарий и архитектурные подходы для эффективного управления производительностью как на уровне компонентов, так и приложения в целом.
1. Использование ChangeDetectionStrategy.OnPush
По умолчанию Angular использует стратегию Change Detection Default, при которой каждый компонент проверяется при любом изменении.
OnPush ограничивает проверки только компонентами, где:
-
изменились входные свойства (@Input()),
-
произошло событие внутри компонента,
-
вызван markForCheck() вручную.
@Component({
selector: 'app-item',
changeDetection: ChangeDetectionStrategy.OnPush,
...
})
export class ItemComponent {}
Это значительно снижает количество запусков Change Detection и уменьшает нагрузку на CPU.
2. Lazy Loading модулей
Ленивая загрузка позволяет загружать части приложения только при необходимости, уменьшая первоначальный размер бандла.
const routes: Routes = \[
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
\];
Lazy-модули должны быть полностью изолированы и не содержать общие сервисы, чтобы избежать дублирования зависимостей.
3. Оптимизация шаблонов
-
Избегать сложных выражений в шаблонах: вычислять данные заранее в компоненте.
-
Не использовать function() или .map() в шаблоне (они пересоздаются на каждый рендер).
-
Минимизировать использование *ngIf и *ngFor в одной обёртке: при необходимости — выносить в отдельные компоненты.
-
Использовать trackBy в *ngFor для предотвращения перерендера всего списка.
<div \*ngFor="let item of items; trackBy: trackById">
{{ item.name }}
</div>
trackById(index: number, item: any) {
return item.id;
}
4. Разделение кода (Code Splitting)
Angular CLI по умолчанию использует Webpack и делит код на чанки. Это можно усилить:
-
Ленивая загрузка не только модулей, но и компонентов с loadComponent().
-
Динамический импорт изображений, переводов, heavy-библиотек и т.п.
loadComponent = () => import('./lazy.component').then(c => c.LazyComponent);
5. Асимметричная загрузка стилей и скриптов
В angular.json:
-
Основные стили — в "styles", подгружаются сразу.
-
Локальные или редко используемые — через динамическую загрузку:
loadStyle(url: string) {
const link = document.createElement('link');
link.href = url;
link.rel = 'stylesheet';
document.head.appendChild(link);
}
6. Использование Web Workers
Web Workers позволяют выполнять тяжёлые вычисления в фоновом потоке, не блокируя UI.
ng generate web-worker worker
Передача сообщений:
this.worker.postMessage(data);
this.worker.onmessage = ({ data }) => { ... };
Полезно для парсинга больших файлов, изображений, криптографии и т.п.
7. Снижение количества DOM-операций
-
Использовать Renderer2 вместо прямой работы с document.
-
Минимизировать манипуляции DOM во время Change Detection.
-
Использовать ng-container вместо лишних div, когда нужен только структурный шаблон.
8. Использование ngOptimizedImage
С Angular 15+ доступен NgOptimizedImage, который автоматически:
-
Генерирует srcset и sizes,
-
Предзагружает важные изображения,
-
Использует lazy-loading.
<img
ngSrc="image.jpg"
width="600"
height="400"
priority
alt="..." />
9. Использование standalone компонентов
С версии Angular 14 можно использовать компоненты без модулей. Это:
-
уменьшает избыточность в NgModules,
-
повышает tree-shaking,
-
ускоряет компиляцию и загрузку.
@Component({
standalone: true,
imports: \[CommonModule\],
templateUrl: './comp.html'
})
export class StandaloneComponent {}
10. Аудит и анализ сборки
Использовать команду:
ng build --prod --stats-json
Затем с помощью webpack-bundle-analyzer проанализировать:
npx webpack-bundle-analyzer dist/stats.json
Искать тяжёлые пакеты, неиспользуемые зависимости, повторяющиеся модули.
11. Caching & HTTP оптимизация
-
Использовать HttpClient с RxJS кешированием (shareReplay, tap, cacheMap).
-
Добавлять заголовки Cache-Control с бэкенда.
-
Кэшировать переводчики (i18n), конфиги и метаданные на клиенте.
12. SSR (Server-Side Rendering) + Prerendering
Использование Angular Universal позволяет отрисовывать HTML на сервере, что:
-
ускоряет Time-to-First-Byte,
-
улучшает SEO,
-
ускоряет начальную загрузку.
Можно использовать гибридную стратегию:
-
SSR для главных страниц,
-
lazy loading + клиентский рендеринг — для остальных.
13. Снижение зоновой активности (NgZone)
Если определённые процессы не требуют Change Detection:
- использовать runOutsideAngular():
this.zone.runOutsideAngular(() => {
element.addEventListener('scroll', this.handler);
});
- Или полностью отключить zone.js и управлять обновлением вручную через ChangeDetectorRef.
14. Использование detach() и detectChanges()
Если компонент статичен, можно временно отключить его от Change Detection:
constructor(private cdr: ChangeDetectorRef) {}
ngOnInit() {
this.cdr.detach();
}
Обновлять вручную:
this.cdr.detectChanges();
15. Использование Signals (Angular 17+)
Signals — новая реактивная модель, позволяющая:
-
избавиться от лишних @Input() и подписок,
-
избегать избыточных CD-проверок,
-
обновлять только необходимые компоненты.
readonly counter = signal(0);
increment() {
this.counter.update(v => v + 1);
}
Signals автоматически интегрированы с OnPush и zone-less режимом.
16. Оптимизация анимаций
-
Использовать AnimationBuilder или Web Animations API напрямую.
-
Удалять неиспользуемые состояния анимаций.
-
Использовать :enter, :leave осторожно, особенно в больших списках.
17. Разделение окружения (Dev vs Prod)
Сборка с флагом --configuration production включает:
-
AOT-компиляцию,
-
Minification + Tree Shaking,
-
Disable DebugInfo,
-
Optimize zone.js patches.
Оптимизация Angular-приложения требует комплексного подхода: от шаблонов и логики до сетевых запросов и архитектурных решений. Комбинация ленивой загрузки, Change Detection с OnPush, сигнальной модели и правильной сборки позволяет достигать высокой производительности даже в крупных приложениях.