Как оптимизировать производительность Angular-приложения

Как оптимизировать производительность Angular-приложения
Медленный Angular бьёт по первому экрану, по индексации и по спискам в админке. Ниже приёмы, которые меряются до и после: бандл, LCP, время рендера.
1. Ленивая загрузка модулей
Первый экран должен открываться быстро. Ленивая загрузка модулей подтягивает куски приложения только когда они нужны.
Пример реализации:
// app-routing.module.ts
const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
},
{
path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule)
}
];
Эффект ленивой загрузки зависит от структуры приложения. Сравнивайте размер initial bundle, LCP и время до интерактивности на одном наборе устройств до и после изменения.
2. ChangeDetectionStrategy.OnPush
По умолчанию Angular проверяет все компоненты при любом событии. С ChangeDetectionStrategy.OnPush компонент перепроверяется, когда меняются входные данные (@Input). Проверок меньше.
@Component({
selector: 'app-product-card',
templateUrl: './product-card.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProductCardComponent {
@Input() product: Product;
}
3. Trackby в ngFor
Вешайте trackBy на *ngFor: Angular узнаёт строку по id, а не по месту в списке. DOM дёргается меньше.
<div *ngFor="let item of items; trackBy: trackByFn">
{{ item.name }}
</div>
trackByFn(index: number, item: any): number {
return item.id;
}
Для больших списков проверяйте время рендеринга профилировщиком и фиксируйте одинаковый объём данных в контрольном сценарии.
4. Виртуальная прокрутка
Для приложений с длинными списками данных реализуйте виртуальную прокрутку с помощью CDK Virtual Scroll, которая рендерит только те элементы, которые видны пользователю.
<cdk-virtual-scroll-viewport itemSize="50" class="viewport">
<div *cdkVirtualFor="let item of items" class="item">
{{ item.name }}
</div>
</cdk-virtual-scroll-viewport>
5. Angular Universal (SSR)
SSR собирает HTML на сервере. Первый экран приходит уже нарисованным, поисковику проще индексировать.
ng add @nguniversal/express-engine
6. Оптимизация бандлов
6.1 Анализ размера
Используйте webpack-bundle-analyzer для анализа размера вашего бандла:
ng build --stats-json
npx webpack-bundle-analyzer dist/stats.json
6.2 Tree Shaking
Убедитесь, что вы импортируете только необходимые модули:
// Вместо этого
import * as _ from 'lodash';
// Используйте это
import { debounce } from 'lodash-es';
7. Оптимизация Angular-pipe
Используйте чистые (pure) pipe для трансформации данных вместо методов компонента или импульсивных вычислений в шаблоне.
@Pipe({
name: 'filterProducts',
pure: true
})
export class FilterProductsPipe implements PipeTransform {
transform(products: Product[], term: string): Product[] {
return term
? products.filter(p => p.name.toLowerCase().includes(term.toLowerCase()))
: products;
}
}
8. Избегайте утечек памяти
Правильно отписывайтесь от Observable, особенно в компонентах, которые часто создаются и уничтожаются:
export class SearchComponent implements OnInit, OnDestroy {
private destroy$ = new Subject();
ngOnInit() {
this.searchService.search()
.pipe(takeUntil(this.destroy$))
.subscribe(results => this.results = results);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
9. Оптимизация шаблонов
Избегайте тяжелых вычислений в шаблонах и множественных привязок:
<!-- Плохо -->
<div *ngFor="let item of getFilteredItems()">
{{ item.name }}
</div>
<!-- Хорошо -->
<div *ngFor="let item of filteredItems">
{{ item.name }}
</div>
// Вычисляем один раз и храним результат
ngOnInit() {
this.filteredItems = this.getFilteredItems();
}
10. Профилирование и измерение
Регулярно измеряйте производительность вашего приложения с помощью инструментов Chrome DevTools, Lighthouse и Angular DevTools. Это поможет вам выявить узкие места и оценить эффективность оптимизаций.
Пример из практики
В админке ритейлера список из тысяч товаров открывался 3,5 секунды. Виртуальный скролл, OnPush и trackBy ужали рендер до 300 мс.
Что измерять
Без замера «оптимизация» - гадание. Смотрите LCP, размер initial bundle и время рендера списка на одном и том же устройстве до и после правки.
Если список в админке тормозит - пришлите профилировщик, разберём по кадрам. Контакт: форма оценки.
Нужна предварительная оценка похожего проекта?
Опишите задачу - подготовим диапазон бюджета и сроков или предложим следующий шаг.
Оставьте контакт - перезвоним
Достаточно телефона, email или Telegram. Описание задачи, бюджет и сроки - по желанию.