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

Как оптимизировать производительность 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. Описание задачи, бюджет и сроки - по желанию.

Обычно отвечаем в рабочее время. Контакты и текст заявки не уходят в Яндекс Метрику.
Нужен короткий ответ?+7 (351) 220-99-41Telegram