Чистые и нечистые пайпы

Пайпы (pipes) в Angular предоставляют удобный способ трансформации данных в шаблонах без изменения исходных данных. Они позволяют применять форматирование, фильтрацию и другие преобразования непосредственно в HTML-шаблонах. Важным аспектом работы пайпов является различие между чистыми (pure) и нечистыми (impure) пайпами, что влияет на производительность приложения и поведение обновления данных.


Определение чистых и нечистых пайпов

Чистый пайп — это пайп, который выполняет трансформацию данных исключительно на основе входных аргументов. Angular вызывает чистый пайп только тогда, когда изменяется ссылка на входное значение. Если входное значение — примитив (число, строка, булев тип), то любое его изменение вызывает обновление. Если входное значение — объект или массив, обновление произойдёт только при изменении ссылки на объект, а не при изменении его содержимого.

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


Синтаксис и объявление пайпов

Пайп создаётся с помощью декоратора @Pipe и класса, реализующего интерфейс PipeTransform:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'examplePipe',
  pure: true // по умолчанию пайпы чистые
})
export class ExamplePipe implements PipeTransform {
  transform(value: any, ...args: any[]): any {
    // логика трансформации
    return value;
  }
}

Ключевой момент — свойство pure.

  • pure: true делает пайп чистым.
  • pure: false превращает пайп в нечистый.

Поведение чистых пайпов

Чистый пайп пересчитывается только при изменении ссылки на входное значение. Пример использования:

@Component({
  selector: 'app-root',
  template: `
    <p>{{ user | json }}</p>
    <button (click)="updateUserName()">Изменить имя</button>
  `
})
export class AppComponent {
  user = { name: 'Alice', age: 25 };

  updateUserName() {
    // ссылка объекта не изменяется
    this.user.name = 'Bob';
  }
}

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

updateUserName() {
  this.user = { ...this.user, name: 'Bob' };
}

Поведение нечистых пайпов

Нечистый пайп реагирует на любое изменение, включая внутренние модификации объектов или массивов:

@Pipe({
  name: 'impureExample',
  pure: false
})
export class ImpureExamplePipe implements PipeTransform {
  transform(value: any): any {
    console.log('Pipe executed');
    return value;
  }
}

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

updateUserName() {
  this.user.name = 'Charlie'; // Pipe выполнится несмотря на неизменную ссылку
}

Применение и оптимизация

Чистые пайпы лучше использовать для:

  • Форматирования данных (даты, валюты, числа).
  • Преобразования статических коллекций.
  • Минимизации количества вызовов трансформаций.

Нечистые пайпы нужны для:

  • Фильтрации массивов, где элементы могут динамически меняться.
  • Отображения данных из сервисов, обновляющихся без изменения ссылки.
  • Случаев, когда невозможно контролировать создание новых объектов.

Рекомендации по производительности:

  • Стараться использовать чистые пайпы по умолчанию.
  • Ограничивать использование нечистых пайпов только там, где это действительно необходимо.
  • При работе с массивами и объектами чаще обновлять ссылку вместо изменения существующего объекта.

Примеры чистых и нечистых пайпов

Чистый пайп для форматирования строки:

@Pipe({
  name: 'uppercase',
  pure: true
})
export class UppercasePipe implements PipeTransform {
  transform(value: string): string {
    return value.toUpperCase();
  }
}

Нечистый пайп для фильтрации массива по динамическому условию:

@Pipe({
  name: 'filterByStatus',
  pure: false
})
export class FilterByStatusPipe implements PipeTransform {
  transform(items: any[], status: string): any[] {
    return items.filter(item => item.status === status);
  }
}

Важные моменты при проектировании

  1. Чистые пайпы упрощают тестирование, так как они детерминированы и не зависят от внешних изменений.
  2. Нечистые пайпы могут вызывать лишние вычисления, поэтому нужно внимательно подходить к их применению в больших списках.
  3. Изменение ссылок на объекты — стандартная практика для работы с чистыми пайпами в реактивных приложениях.

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