Angular — это мощный и популярный фреймворк для создания динамических веб-приложений. Однако по мере увеличения размера и сложности приложений могут возникать узкие места в производительности, влияющие на удобство работы пользователей. В этой статье мы рассмотрим различные методы и рекомендации по повышению производительности приложений Angular, обеспечив их бесперебойную и эффективную работу.

Оглавление:

  1. Оптимизация обнаружения изменений
    1.1. Стратегия обнаружения изменений OnPush
    1.2. Неизменяемые структуры данных
    1.3. Использование trackBy с ngFor
  2. Отложенная загрузка и разделение кода
    2.1. Ленивая загрузка модулей
    2.2. Разделение кода с помощью динамического импорта
  3. Компиляция AOT
    3.1. Опережение времени (AOT) и точно в срок (JIT)
    3.2. Настройка компиляции AOT
  4. Оптимизация пакета
    4.1. Встряхивание дерева
    4.2. Минификация и укрупнение
    4.3. Исходные карты
  5. Оптимизация CSS
    5.1. Используйте препроцессоры SCSS и CSS
    5.2. Уменьшите селекторы CSS и специфичность
    5.3. Применить сброс и нормализацию CSS
  6. Профилирование и аудит производительности
    6.1. Профилировщик производительности Angular
    6.2. Chrome DevTools и Lighthouse
  7. Виртуальная прокрутка и бесконечная загрузка
    7.1. Виртуальная прокрутка с помощью CDK
    7.2. Реализация бесконечной загрузки
  8. Кэширование и управление данными
    8.1. Кэширование на стороне клиента с помощью сервис-воркеров
    8.2. Интеллектуальная загрузка данных с помощью NgRx
  9. Оптимизация изображений и ресурсов
    9.1. Сжатие изображений
    9.2. Формат WebP для поддерживаемых браузеров
  10. Функции PWA для повышения производительности
    10.1. Автономная поддержка с помощью Service Workers
    10.2. Всплывающее уведомление
  11. Оптимизация сетевых запросов
    11.1. HTTP-перехватчики
    11.2. Минимизируйте запросы и полезные нагрузки
  12. Управление памятью и отказ от подписки
    12.1. Утечки памяти и управление подпиской
    12.2. Отписка в ngOnDestroy
  13. Тестирование производительности и сравнительный анализ
    13.1. Инструменты тестирования производительности
    13.2. Установка контрольных показателей производительности
  14. Визуализация на стороне сервера (SSR)
    14.1. Угловой универсальный
    14.2. Плюсы и минусы ССР
  15. Постоянный мониторинг и оптимизация
    15.1. Автоматические проверки производительности
    15.2. Бюджеты производительности
  16. Заключение

1. Оптимизируйте обнаружение изменений

Механизм обнаружения изменений Angular отвечает за обнаружение изменений в данных и соответствующее обновление представления. Однако при неоптимальном использовании он может стать неэффективным, что приведет к ненужным проверкам и обновлениям.

1.1. Стратегия обнаружения изменений OnPush

Стратегия обнаружения изменений по умолчанию в Angular называется «По умолчанию» или «CheckAlways». Это означает, что каждый раз, когда в приложении происходит какое-либо изменение, Angular запускает цикл обнаружения изменений для всех компонентов, независимо от того, затронуты они изменением или нет. Это может привести к проблемам с производительностью, особенно в больших приложениях.

Чтобы повысить производительность, вы можете использовать стратегию обнаружения изменений «OnPush» для определенных компонентов. Стратегия «OnPush» указывает Angular запускать обнаружение изменений для компонента только при изменении его входных свойств или при возникновении события внутри компонента.

Чтобы использовать стратегию «OnPush», установите для свойства changeDetection компонента значение ChangeDetectionStrategy.OnPush:

import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-example-component',
  templateUrl: './example.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleComponent {
  // Component logic here
}

Используя «OnPush», вы сокращаете ненужные циклы обнаружения изменений и повышаете производительность компонента.

1.2. Неизменяемые структуры данных

Обнаружение изменений в Angular работает путем сравнения текущих данных с предыдущими данными, чтобы определить, есть ли какие-либо изменения. Если вы используете изменяемые структуры данных, такие как массивы или объекты, изменение их свойств может привести к срабатыванию обнаружения изменений, даже если фактические данные остаются прежними.

Чтобы смягчить это, рассмотрите возможность использования неизменяемых структур данных, в которых данные не могут быть изменены после создания. Такие библиотеки, как Immutable.js или Immer, помогут вам работать с неизменяемыми данными более удобным способом.

Например, с помощью Immer вы можете создавать неизменяемые копии своих данных, но при этом иметь возможность изменять их в удобочитаемой и простой форме:

import { produce } from 'immer';

const originalData = { count: 0 };
const newData = produce(originalData, (draft) => {
  draft.count += 1;
});
console.log(originalData.count); // Output: 0
console.log(newData.count); // Output: 1

1.3. Использование trackBy с ngFor

При использовании *ngFor для перебора списка элементов Angular нужен способ отслеживать изменения в

элементы и эффективно обновлять DOM. По умолчанию Angular использует индекс элемента в массиве в качестве механизма отслеживания. Однако это может привести к проблемам с производительностью, особенно при добавлении, удалении или изменении порядка элементов в списке.

Чтобы оптимизировать *ngFor, используйте функцию trackBy, чтобы указать уникальный идентификатор для каждого элемента:

<app-item *ngFor="let item of items; trackBy: trackItemById"></app-item>

В компоненте определите функцию trackItemById, чтобы возвращать уникальный идентификатор для каждого элемента:

import { Component } from '@angular/core';

@Component({
  selector: 'app-example-component',
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  items: Item[];
  trackItemById(index: number, item: Item): number {
    return item.id;
  }
}

С помощью trackBy Angular может эффективно обновлять DOM при изменении элементов, что значительно повышает производительность.

2. Ленивая загрузка и разделение кода

Загрузка всего приложения сразу может привести к увеличению времени первоначальной загрузки, что повлияет на воспринимаемую производительность вашего приложения. Ленивая загрузка и разделение кода — это методы загрузки только необходимых частей приложения, когда они необходимы, что сокращает время первоначальной загрузки.

2.1. Ленивая загрузка модулей

Angular позволяет разделить ваше приложение на несколько модулей и загружать их динамически, используя отложенную загрузку. При отложенной загрузке каждый модуль загружается только тогда, когда пользователь переходит к определенному маршруту, для которого требуется этот модуль.

Чтобы настроить ленивую загрузку, создайте отдельный модуль для каждой функции или раздела вашего приложения и используйте свойство loadChildren в конфигурации маршрутизации:

const routes: Routes = [
  // Normal eager-loaded route
  { path: 'home', component: HomeComponent },
// Lazy-loaded route
  { path: 'lazy', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) },
];

При ленивой загрузке начальный размер пакета уменьшается, и пользователь загружает только те модули, которые он действительно использует.

2.2. Разделение кода с помощью динамического импорта

В дополнение к отложенной загрузке модулей вы можете дополнительно оптимизировать размер пакета вашего приложения с помощью динамического импорта. Динамический импорт позволяет вам загружать части кода вашего приложения по требованию, уменьшая размер исходного пакета.

Чтобы использовать динамический импорт, используйте функцию динамического импорта() для загрузки модулей или компонентов при необходимости:

@Component({
  selector: 'app-example-component',
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  async loadLazyComponent() {
    const { LazyComponent } = await import('./lazy/lazy.component');
    // Do something with the LazyComponent, e.g., render it dynamically
  }
}

Используя динамический импорт, вы можете отложить загрузку второстепенного кода до тех пор, пока он не потребуется, что приведет к ускорению начальной загрузки.

3. Компиляция АОТ

Компиляция с опережением времени (AOT) — это метод оптимизации, который компилирует шаблоны и компоненты Angular в процессе сборки, а не во время выполнения, как компиляция Just-in-Time (JIT). Компиляция AOT предлагает несколько преимуществ, включая более быстрое время загрузки, меньший размер пакета и повышенную безопасность.

3.1. Опережение времени (AOT) и точно в срок (JIT)

При JIT-компиляции шаблоны Angular компилируются и интерпретируются браузером во время выполнения, что может привести к замедлению начальной загрузки. С другой стороны, компиляция AOT переводит шаблоны и компоненты в JavaScript в процессе сборки, что приводит к ускорению загрузки и повышению производительности во время выполнения.

Чтобы включить компиляцию AOT, используйте флаг — aot при запуске команды сборки Angular CLI:

ng build --prod --aot

Включив компиляцию AOT, вы можете улучшить общую производительность и время загрузки вашего приложения Angular.

3.2. Настройка компиляции AOT

При использовании компиляции AOT важно убедиться, что ваше приложение совместимо и не содержит каких-либо потенциальных проблем, которые могут возникнуть в процессе сборки. Некоторые функции Angular, такие как динамические URL-адреса шаблонов или привязки классов CSS на основе строк, несовместимы с AOT и требуют настройки.

Angular предоставляет удобный инструмент CLI под названием ngc, который может проверить совместимость вашего приложения с компиляцией AOT. Используйте следующую команду для запуска компилятора ngc:

ngc

Запуск ngc проверит любые потенциальные проблемы и предоставит рекомендации по их устранению.

4. Пакетная оптимизация

Оптимизация пакетов вашего приложения имеет решающее значение для повышения производительности вашего приложения Angular. Уменьшая размер пакетов, вы можете ускорить загрузку и повысить общую производительность.

4.1. Сотрясение дерева

Встряхивание дерева — это процесс, который удаляет неиспользуемый код из ваших пакетов в процессе сборки. Это гарантирует, что только тот код, который фактически используется в вашем приложении, будет включен в окончательный пакет, что уменьшит его размер.

Чтобы включить встряхивание дерева, убедитесь, что вы используете модули ES6 в своем коде, так как это позволяет инструментам сборки идентифицировать и удалять неиспользуемый код.

4.2. Минимизация и укрупнение

Минификация и сокращение — это методы, которые уменьшают размер ваших файлов JavaScript и CSS, удаляя ненужные символы, такие как пробелы и комментарии. Минификация может значительно уменьшить размер

ваших пакетов и сократить время загрузки.

Angular CLI автоматически выполняет минификацию и удаление при создании приложения для производства:

ng build --prod

Включив флаг —prod, Angular CLI применит минимизацию и сокращение к вашим пакетам.

4.3. Исходные карты

Хотя минимизация и сокращение необходимы для уменьшения размера пакета, они могут усложнить отладку, поскольку код становится трудным для чтения. Карты исходного кода обеспечивают сопоставление между минимизированным кодом и исходным кодом, позволяя вам отлаживать и проверять код в его исходной форме.

Исходные карты автоматически генерируются Angular CLI при создании приложения для производства:

ng build --prod

Однако, чтобы убедиться, что исходные карты включены в сборку, убедитесь, что для параметра «sourceMap» установлено значение true в вашем файле angular.json:

{
  "projects": {
    "your-project-name": {
      "architect": {
        "build": {
          "options": {
            "sourceMap": true
          }
        }
      }
    }
  }
}

5. Оптимизация CSS

Производительность вашего приложения Angular зависит не только от JavaScript; CSS также играет важную роль. Оптимизация вашего CSS может привести к ускорению времени рендеринга и улучшению взаимодействия с пользователем.

5.1. Используйте препроцессоры SCSS и CSS

Использование препроцессора CSS, такого как SCSS, позволяет более эффективно организовать код CSS и упростить его обслуживание. SCSS предоставляет такие функции, как переменные, примеси и вложенные правила, которые помогут вам писать более чистый и модульный код CSS.

Чтобы использовать SCSS в вашем приложении Angular, вам необходимо установить пакет sass:

npm install sass --save-dev

После установки пакета sass вы можете начать использовать файлы SCSS (с расширением .scss) в своем приложении.

5.2. Уменьшите селекторы и специфичность CSS

Селекторы CSS с высокой специфичностью могут замедлить время рендеринга, особенно когда браузеру приходится применять стили к нескольким элементам. Старайтесь, чтобы ваши селекторы CSS были как можно более простыми, и избегайте использования чрезмерно конкретных правил.

Кроме того, попробуйте уменьшить количество селекторов CSS в таблицах стилей. Чем больше у вас селекторов, тем больше работы нужно сделать браузеру, чтобы применить стили.

5.3. Применить сброс и нормализацию CSS

Браузеры применяют стили по умолчанию к элементам HTML, что может привести к несовместимости стилей в разных браузерах. Чтобы обеспечить постоянную отправную точку для ваших стилей, рассмотрите возможность использования сброса CSS или нормализации таблицы стилей.

Сброс CSS устанавливает для всех свойств CSS согласованный базовый уровень, в то время как normalize обеспечивает более тонкие и согласованные между браузерами стили.

Включите сброс или нормализацию CSS в свои таблицы стилей, чтобы обеспечить согласованную отправную точку для вашего приложения:

/* Example CSS Reset */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* More styles and selectors can be added as needed */

6. Профилирование производительности и аудит

Регулярное профилирование и аудит производительности вашего приложения Angular может помочь выявить потенциальные узкие места и области для улучшения. Несколько инструментов и методов могут помочь вам проанализировать производительность вашего приложения.

6.1. Угловой профилировщик производительности

Angular поставляется со встроенными инструментами профилирования производительности, которые помогут вам понять, как работает ваше приложение. Чтобы получить доступ к профилировщику производительности Angular, добавьте ?profile=true к URL вашего приложения:

http://localhost:4200/?profile=true

Это активирует профилировщик производительности, и вы сможете использовать инструменты разработчика для проверки результатов профилирования.

6.2. Chrome DevTools и Lighthouse

Chrome DevTools предоставляет различные функции, связанные с производительностью, которые могут помочь вам выявить проблемы с производительностью в вашем приложении. Вкладка «Производительность» позволяет записывать и анализировать показатели производительности, такие как время загрузки, выполнение JavaScript и производительность рендеринга.

Кроме того, вы можете использовать Lighthouse, инструмент с открытым исходным кодом от Google, для проверки производительности вашего приложения и получения действенных рекомендаций по улучшению. Lighthouse предоставляет исчерпывающий отчет о различных аспектах производительности вашего приложения, включая производительность, доступность, SEO и многое другое.

7. Виртуальная прокрутка и бесконечная загрузка

Если ваше приложение работает с большими списками или наборами данных, виртуальная прокрутка и бесконечная загрузка могут значительно повысить производительность за счет загрузки и рендеринга только видимых элементов.

7.1. Виртуальная прокрутка с CDK

Комплект разработчика компонентов Angular (CDK) предоставляет модуль виртуальной прокрутки, который обеспечивает виртуальную прокрутку для списков, таблиц или других элементов контейнера. Виртуальная прокрутка загружает только те элементы, которые в данный момент видны на экране, уменьшая количество элементов DOM и повышая производительность.

Чтобы использовать виртуальную прокрутку, вам необходимо установить пакет @angular/cdk:

npm install @angular/cdk --save

Затем импортируйте ScrollingModule из пакета @angular/cdk/scrolling и добавьте его в модуль вашего приложения:

import { NgModule } from '@angular/core';
import { ScrollingModule } from '@angular/cdk/scrolling';

@NgModule({
  imports: [ScrollingModule],
})
export class AppModule {}

Теперь вы можете использовать компонент cdk-virtual-scroll-viewport, чтобы включить виртуальную прокрутку для списка элементов:

<cdk-virtual-scroll-viewport itemSize="50" class="example-viewport">
  <div *cdkVirtualFor="let item of items" class="example-item">
    {{ item }}
  </div>
</cdk-virtual-scroll-viewport>

Используя виртуальную прокрутку, вы можете эффективно обрабатывать большие наборы данных, не влияя на производительность приложения.

7.2. Реализация бесконечной загрузки

Бесконечная загрузка — это метод, при котором новые данные загружаются по мере того, как пользователь прокручивает страницу вниз, что обеспечивает бесперебойную работу без необходимости ручной разбивки на страницы или явной загрузки дополнительных данных.

Чтобы реализовать бесконечную загрузку, вам нужно определить, когда пользователь прокручивает страницу до конца, и инициировать загрузку дополнительных данных.

Во-первых, вам нужно обработать событие прокрутки в вашем компоненте:

import { Component, HostListener } from '@angular/core';

@Component({
  selector: 'app-example-component',
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  items: Item[] = [];
  isLoading = false;
  @HostListener('window:scroll', ['$event'])
  onScroll(event: Event): void {
    // Check if the user has scrolled to the bottom of the page
    const isAtBottom = window.innerHeight + window.scrollY >= document.body.scrollHeight;
    if (isAtBottom && !this.isLoading) {
      this.loadMoreData();
    }
  }
  loadMoreData(): void {
    // Load more data here (e.g., from an API) and add it to the items array
    // Set isLoading to true while loading and false when the data is loaded
  }
}

В приведенном выше примере мы используем декоратор HostListener для прослушивания события scroll в окне. Когда пользователь прокручивает страницу вниз, вызывается метод onScroll, после чего мы можем инициировать загрузку дополнительных данных.

Реализуя бесконечную загрузку, вы можете обеспечить более плавное взаимодействие с пользователем и предотвратить проблемы с производительностью, связанные с одновременной загрузкой больших наборов данных.

8. Кэширование и управление данными

Кэширование и эффективное управление данными необходимы для повышения производительности вашего приложения Angular, особенно при работе с данными из API или внешних источников.

8.1. Кэширование на стороне клиента с помощью Service Workers

Сервисные работники — это сценарии, которые работают в фоновом режиме и позволяют вашему приложению кэшировать данные и активы. С помощью сервис-воркеров вы можете хранить определенные ресурсы локально на устройстве пользователя, уменьшая необходимость получать их из сети каждый раз, когда пользователь посещает ваше приложение.

Чтобы реализовать кэширование на стороне клиента с помощью сервис-воркеров, вам нужно создать скрипт сервис-воркера и зарегистрировать его в своем приложении.

Сначала создайте файл сервис-воркера (например, sw.js) и добавьте логику кэширования:

const CACHE_NAME = 'my-app-cache-v1';
const urlsToCache = ['/index.html', '/styles.css', '/app.js'];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll(urlsToCache);
    })
  );
});
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      // Cache hit - return the cached response
      if (response) {
        return response;
      }
      // If the request is not cached, fetch it from the network
      return fetch(event.request);
    })
  );
});

В приведенном выше примере мы кэшируем файлы index.html, styles.css и app.js, когда сервис-воркер установлен. Затем, когда происходит событие выборки (т. е. когда приложение пытается получить ресурс), сервис-воркер перехватывает запрос и проверяет, существует ли он в кеше. Если это так, кэшированный ответ возвращается; в противном случае запрос извлекается из сети.

Затем зарегистрируйте сервис-воркера в файле main.ts вашего приложения:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(() => console.log('Service Worker registered successfully.'))
    .catch((error) => console.error('Error registering Service Worker:', error));
}

Внедрив кэширование на стороне клиента с помощью сервис-воркеров, вы можете значительно повысить производительность своего приложения, особенно для пользователей с более медленными или ненадежными сетевыми подключениями.

8.2. Интеллектуальная загрузка данных с помощью NgRx

NgRx — это библиотека управления состоянием для приложений Angular, которая позволяет вам управлять данными и состоянием вашего приложения в централизованном хранилище. Используя NgRx, вы можете реализовать интеллектуальные стратегии загрузки данных, такие как отложенная загрузка или выборка данных по запросу, для повышения производительности.

Чтобы использовать NgRx, вам необходимо установить пакет @ngrx/store:

npm install @ngrx/store --save

Затем настройте хранилище, действия, редьюсеры и эффекты в соответствии с требованиями управления данными вашего приложения.

Например, вы можете использовать NgRx для реализации отложенной загрузки данных, когда пользователь переходит к определенному маршруту:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { loadItems } from './store/actions/items.actions';

@Component({
  selector: 'app-example-component',
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  constructor(private store: Store) {}
  ngOnInit(): void {
    this.store.dispatch(loadItems());
  }
}

В этом примере действие loadItems отправляется при инициализации компонента, запуская загрузку необходимых данных из хранилища или внешнего API.

Используя NgRx и интеллектуальные методы загрузки данных, вы можете гарантировать, что ваше приложение эффективно загружает данные и управляет ими, что приводит к повышению производительности и более плавному взаимодействию с пользователем.

9. Оптимизация изображений и ресурсов

Изображения и другие ресурсы могут значительно увеличить общий размер вашего приложения, влияя на время загрузки. Оптимизация ваших изображений и ресурсов необходима для повышения производительности.

9.1. Сжатие изображения

Сжатие изображений может значительно уменьшить их размер без ущерба для качества. Вы можете использовать различные инструменты и методы сжатия изображений, чтобы оптимизировать изображения, прежде чем включать их в свое приложение.

Например, вы можете использовать онлайн-инструменты сжатия изображений, такие как TinyPNG или ImageOptim, чтобы уменьшить размер ваших изображений.

Кроме того, Angular CLI обеспечивает встроенную поддержку оптимизации изображений в процессе сборки. Включив флаг —prod, CLI автоматически оптимизирует изображения в вашем приложении:

ng build --prod

9.2. Формат WebP для поддерживаемых браузеров

WebP — это современный формат изображений, разработанный Google, который обеспечивает превосходное сжатие и качество по сравнению с традиционными форматами изображений, такими как JPEG и PNG. Он поддерживается большинством современных браузеров, включая Chrome, Firefox и Opera.

Чтобы показывать изображения WebP в поддерживаемых браузерах, вы можете использовать элемент picture с элементом source:

<picture>
  <source srcset="path/to/image.webp" type="image/webp">
  <img src="path/to/image.jpg" alt="Image">
</picture>

Используя изображения WebP, вы можете дополнительно уменьшить размер изображений вашего приложения и сократить время загрузки для пользователей в поддерживаемых браузерах.

10. Функции PWA для повышения производительности

Прогрессивные веб-приложения (PWA) — это веб-приложения, которые используют современные веб-технологии, чтобы предоставить пользователям более похожие на приложения возможности. PWA могут значительно повлиять на производительность вашего приложения, особенно с точки зрения автономной поддержки и фоновой синхронизации.

10.1. Автономная поддержка с помощью Service Workers

Как упоминалось ранее, сервис-воркеры включают кэширование на стороне клиента и могут обеспечить автономную поддержку вашего приложения. Кэшируя критически важные ресурсы, такие как файлы HTML, CSS и JavaScript, вы можете гарантировать, что пользователи по-прежнему смогут получить доступ к вашему приложению, даже если они не в сети.

Кроме того, вы можете использовать Cache Storage API для кэширования динамических данных из API, позволяя пользователям получать доступ к определенным частям вашего приложения, даже если у них нет подключения к Интернету.

10.2. Всплывающее уведомление

Push-уведомления — важная функция PWA, которая может помочь повторно привлечь пользователей и предоставить своевременные обновления. Внедряя push-уведомления, вы можете уведомлять пользователей о новом содержимом, обновлениях или другой важной информации, даже если они не используют активно ваше приложение.

Чтобы включить push-уведомления, вам необходимо реализовать службу push-уведомлений на стороне сервера и обрабатывать процесс подписки и уведомлений в вашем приложении Angular.

Включив функции PWA в свое приложение, вы можете повысить его производительность, взаимодействие с пользователем и взаимодействие с ним.

11. Оптимизация сетевых запросов

Сетевые запросы, такие как вызовы API и выборка данных, могут повлиять на производительность вашего приложения Angular. Оптимизация того, как вы делаете и обрабатываете сетевые запросы, может привести к более быстрому отклику приложения.

11.1. HTTP-перехватчики

Angular предоставляет перехватчики HTTP, которые позволяют перехватывать и изменять HTTP-запросы и ответы. Перехватчики полезны для различных целей, таких как добавление маркеров аутентификации к запросам, обработка ошибок или кэширование ответов.

Например, вы можете использовать перехватчик для добавления токена аутентификации к каждому исходящему запросу:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Add the authentication token to the request
    const authToken = 'your-auth-token';
    const authRequest = request.clone({ setHeaders: { Authorization: `Bearer ${authToken}` } });
    return next.handle(authRequest);
  }
}

Чтобы использовать перехватчик, вам необходимо предоставить его в модуле вашего приложения:

import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth.interceptor';

@NgModule({
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
  ],
})
export class AppModule { }

11.2. Минимизируйте запросы и полезные нагрузки

Сокращение количества сетевых запросов и оптимизация полезной нагрузки могут значительно повысить производительность вашего приложения Angular.

Например, рассмотрите возможность объединения нескольких запросов API в один запрос с использованием пакетных конечных точек или запросов GraphQL. Это может сократить количество обращений к серверу и улучшить общее время загрузки.

Кроме того, стремитесь свести к минимуму размер данных, отправляемых между сервером и клиентом. Избегайте отправки ненужных данных в ответах API и рассмотрите возможность использования методов сжатия, таких как Gzip, для уменьшения размера полезной нагрузки.

12. Управление памятью и отписка

Правильное управление памятью и подписками имеет решающее значение для поддержания производительности и стабильности вашего приложения Angular.

12.1. Утечки памяти и управление подписками

Неправильно управляемые подписки могут привести к утечке памяти в вашем приложении. Когда компонент уничтожается, важно отказаться от всех подписок, чтобы предотвратить утечку памяти и ненужную обработку.

Вы можете использовать метод unsubscribe() для отказа от подписки в хуке жизненного цикла OnDestroy:

import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-example-component',
  templateUrl: './example.component.html',
})
export class ExampleComponent implements OnDestroy {
  private dataSubscription: Subscription;
  constructor(private dataService: DataService) {
    this.dataSubscription = this.dataService.getData().subscribe((data) => {
      // Process the data
    });
  }
  ngOnDestroy(): void {
    this.dataSubscription.unsubscribe();
  }
}

Отписываясь от подписок, вы гарантируете, что ваше приложение освобождает ресурсы, когда они больше не нужны, что приводит к повышению производительности и предотвращает проблемы, связанные с памятью.

12.2. Отписка в ngOnDestroy

Крайне важно всегда отписываться от подписок в хуке жизненного цикла ngOnDestroy. Однако ручное управление подписками может быть сопряжено с ошибками и отнимать много времени, особенно в сложных приложениях.

Чтобы упростить процесс управления подпиской, рассмотрите возможность использования оператора takeUntil из RxJS вместе с субъектом для отслеживания жизненного цикла компонента:

import { Component, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-example-component',
  templateUrl: './example.component.html',
})
export class ExampleComponent implements OnDestroy {
  private unsubscribe$ = new Subject<void>();
  constructor(private dataService: DataService) {
    this.dataService.getData()
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe((data) => {
        // Process the data
      });
  }
  ngOnDestroy(): void {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }
}

С оператором takeUntil подписка автоматически отменяется, когда субъект unsubscribe$ выдает значение, что происходит, когда компонент уничтожается в ловушке жизненного цикла ngOnDestroy.

Используя takeUntil и тему unsubscribe$, вы можете упростить управление подписками и предотвратить утечку памяти в вашем приложении Angular.

13. Тестирование производительности и сравнительный анализ

Регулярное тестирование и сравнение производительности вашего приложения Angular может помочь вам определить области, которые нуждаются в улучшении, и отслеживать влияние оптимизации с течением времени.

13.1. Инструменты тестирования производительности

Несколько инструментов и сред могут помочь вам в тестировании производительности и сравнительном анализе:

  • Lighthouse: как упоминалось ранее, Lighthouse — это инструмент, который проверяет производительность вашего приложения и дает рекомендации по улучшению. Его можно запустить как расширение для браузера или как инструмент командной строки.
  • WebPageTest: WebPageTest позволяет вам тестировать производительность вашего приложения из разных мест и предоставляет подробные показатели и анализ времени загрузки вашего приложения.
  • Google Chrome DevTools: Chrome DevTools предлагает различные функции, связанные с производительностью, такие как вкладка «Производительность» для записи и анализа показателей производительности.
  • Профилировщик производительности Angular: встроенный профилировщик производительности Angular можно использовать для проверки и измерения производительности вашего приложения Angular.

13.2. Установка контрольных показателей производительности

После того, как вы выбрали инструмент для тестирования производительности, вы можете установить контрольные показатели производительности для своего приложения. Сравнительный анализ позволяет вам устанавливать целевые показатели производительности и отслеживать, соответствует ли ваше приложение этим целевым показателям.

Например, вы можете установить ориентиры для следующих показателей:

  • Время загрузки: время, необходимое вашему приложению для загрузки и перехода в интерактивный режим.
  • Время до первого байта (TTFB): время, необходимое серверу для ответа с первым байтом данных.
  • Время до интерактивности (TTI): время, необходимое для того, чтобы ваше приложение стало полностью интерактивным.
  • Самая большая отрисовка содержимого (LCP): время, необходимое для того, чтобы самый большой элемент на странице стал видимым.
  • Совокупное смещение макета (CLS): мера визуальной стабильности страницы, особенно для элементов, которые перемещаются во время загрузки.

Регулярно тестируя свое приложение на соответствие этим эталонным тестам, вы можете выявить снижение производительности и оценить влияние оптимизаций.

14. Рендеринг на стороне сервера (SSR)

Рендеринг на стороне сервера (SSR) — это метод, который визуализирует ваше приложение Angular на сервере перед его отправкой в ​​браузер клиента. SSR может улучшить начальное время загрузки и обеспечить лучшие возможности SEO и обмена в социальных сетях.

14.1. Угловой универсальный

Angular Universal — это фреймворк для рендеринга на стороне сервера в приложениях Angular. Это позволяет вам отображать ваше приложение на сервере, предоставляя предварительно обработанный HTML-ответ браузеру клиента. Последующие взаимодействия в браузере клиента будут обрабатываться стандартным Angular SPA.

Чтобы добавить рендеринг на стороне сервера в ваше приложение Angular, вам необходимо установить пакет @angular/platform-server:

npm install @angular/platform-server --save

Затем вам нужно настроить приложение для SSR, создав серверный модуль и основной файл сервера:

// server.ts (server entry point)
import 'zone.js/node';
import 'reflect-metadata';
import { enableProdMode } from '@angular/core';
import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import * as express from 'express';
import { join } from 'path';

// Import the main server bundle generated by the Angular CLI
import { AppServerModuleNgFactory, LAZY_MODULE_MAP } from './dist/server/main';
enableProdMode();
const app = express();
app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [provideModuleMap(LAZY_MODULE_MAP)],
}));
app.set('view engine', 'html');
app.set('views', join(__dirname, 'dist/browser'));
app.get('*.*', express.static(join(__dirname, 'dist/browser')));
app.get('*', (req, res) => {
  res.render('index', { req });
});
app.listen(4000, () => {
  console.log('Server listening on port 4000');
});

В файле server.ts мы импортируем основной пакет сервера, сгенерированный Angular CLI, и используем ngExpressEngine для рендеринга приложения на сервере.

После того, как ваш сервер настроен, вы можете создать приложение Angular для рендеринга на стороне сервера с помощью интерфейса командной строки Angular:

ng build --prod --app=your-app-name

Флаг --app=your-app-name указывает приложение, которое вы хотите создать для SSR, если у вас есть несколько приложений в вашем проекте Angular.

После создания приложения запустите сервер с помощью команды node:

node server.js

Благодаря Angular Universal и SSR время первоначальной загрузки вашего приложения улучшится, что повысит удобство работы пользователей и возможность обнаружения поисковыми системами.

14.2. Плюсы и минусы ССР

Рендеринг на стороне сервера имеет несколько преимуществ и некоторые недостатки:

Плюсы:

  • Более быстрое время первоначальной загрузки. Предварительный рендеринг вашего приложения на сервере сокращает время, необходимое для загрузки и перехода начальной страницы в интерактивный режим.
  • Улучшение SEO: поисковые системы могут легче сканировать и индексировать предварительно обработанный контент, улучшая SEO и обнаруживаемость поисковыми системами.
  • Улучшенный обмен в социальных сетях: при обмене ссылками на платформах социальных сетей предварительно обработанный контент будет виден, что обеспечивает лучший пользовательский опыт.

Минусы:

  • Повышенная нагрузка на сервер. Рендеринг на стороне сервера может увеличить нагрузку на сервер, особенно для приложений с высоким трафиком. Чтобы справиться с возросшим спросом, необходима надлежащая серверная инфраструктура.
  • Сложность: добавление SSR в существующее приложение Angular может быть сложным и потребовать настройки компонентов, служб и управления состоянием.
  • Больше времени для интерактивного взаимодействия: хотя SSR сокращает время начальной загрузки, оно не устраняет необходимость загрузки и выполнения JavaScript. В результате время до интерактивности может быть больше по сравнению с приложениями, полностью визуализируемыми на стороне клиента.

Необходимость реализации SSR зависит от требований вашего приложения и целей производительности. Для веб-сайтов с большим количеством контента или приложений, которые отдают приоритет SEO, SSR может быть ценным дополнением для повышения производительности и удобства пользователей.

15. Непрерывный мониторинг и оптимизация

Оптимизация производительности приложения Angular — это не разовая задача. Для поддержания высокого уровня производительности необходим непрерывный мониторинг и оптимизация.

15.1. Автоматические проверки производительности

Интегрируйте автоматические проверки производительности в процессы разработки и развертывания. Вы можете использовать такие инструменты, как Lighthouse, WebPageTest или пользовательские сценарии тестирования производительности, чтобы регулярно проверять производительность вашего приложения.

Настройте автоматизированные сценарии или конвейеры CI/CD для запуска проверок производительности после каждого развертывания. Таким образом, вы можете быстро определить любые регрессии производительности и принять меры для их устранения.

15.2. Бюджеты производительности

Установите бюджеты производительности для вашего приложения. Бюджеты производительности определяют максимально допустимые пределы для таких показателей, как размер пакета, время загрузки и другие показатели производительности.

Установив бюджеты производительности, вы можете предотвратить снижение производительности и убедиться, что производительность вашего приложения остается на приемлемом уровне.

16. Заключение

Повышение производительности вашего приложения Angular требует целостного подхода с учетом различных факторов, которые могут повлиять на производительность. Оптимизируя обнаружение изменений, отложенную загрузку модулей и используя компиляцию AOT, вы можете сократить время первоначальной загрузки и размер пакета.

Оптимизация CSS, использование виртуальной прокрутки и бесконечной загрузки, а также интеллектуальное управление данными могут сократить время рендеринга и обработку данных. Кроме того, реализация рендеринга на стороне сервера, использование PWA и управление подписками могут еще больше повысить производительность и удобство работы пользователей.

Непрерывный мониторинг и сравнительный анализ помогают определить области, требующие улучшения, и убедиться, что ваше приложение соответствует поставленным задачам по производительности. Уделяя особое внимание производительности, вы можете создать быстрое, отзывчивое и эффективное приложение Angular, которое понравится вашим пользователям и обеспечит бесперебойную работу.