Для чего нужен @Injectable и как работает DI в Angular?angular-20

@Injectable: назначение и использование

Декоратор @Injectable в Angular выполняет две ключевые функции:

  1. Помечает класс как участвующий в системе Dependency Injection (DI)
    Это означает, что Angular может создавать экземпляры этого класса и внедрять в него зависимости.

  2. Позволяет указать область видимости (scope) сервиса
    Через параметр providedIn можно определить, где будет доступен сервис.

Пример:

@Injectable({
  providedIn: 'root' // Сервис будет singleton на уровне приложения
})
export class DataService {}

Важно: Хотя @Injectable обязателен для сервисов, его можно опустить для компонентов, директив и pipes, так как они уже декорированы @Component, @Directive, @Pipe.

Как работает Dependency Injection в Angular

1. Иерархия инжекторов

Angular создает древовидную структуру инжекторов, соответствующую структуре компонентов:

  • Root Injector (создается при запуске приложения)
  • Module Injectors (для lazy-loaded модулей)
  • Component Injectors (для каждого компонента)

2. Процесс внедрения зависимостей

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

  1. Angular ищет провайдера в инжекторе текущего компонента
  2. Если не найден - поднимается вверх по иерархии компонентов
  3. Если все еще не найден - проверяет модульные инжекторы
  4. В последнюю очередь проверяет root инжектор

3. Типы провайдеров

Зависимости можно регистрировать несколькими способами:

// 1. В декораторе Injectable
@Injectable({ providedIn: 'root' })

// 2. В массиве providers модуля
@NgModule({
  providers: [MyService]
})

// 3. В массиве providers компонента
@Component({
  providers: [MyService]
})

4. Механизм resolution modifiers

Angular предоставляет модификаторы для управления процессом разрешения зависимостей:

  • @Optional() - зависимость не обязательна
  • @Self() - искать только в текущем инжекторе
  • @SkipSelf() - пропустить текущий инжектор
  • @Host() - искать только до host компонента

Пример:

constructor(
  @Optional() private optionalService: OptionalService,
  @Host() private hostService: HostService
) {}

Практические аспекты DI

  1. Дерево инжекторов позволяет:

    • Создавать сервисы с разной областью видимости
    • Переопределять сервисы на разных уровнях
    • Эффективно управлять жизненным циклом объектов
  2. Токены используются для идентификации зависимостей:

    • Классы (наиболее распространенный случай)
    • Строковые токены (для значений, не являющихся классами)
    • InjectionToken (типизированная альтернатива строковым токенам)

Пример InjectionToken:

export const API_URL = new InjectionToken<string>('api.url');

Резюмируем

  1. @Injectable:

    • Маркирует класс как участника DI системы
    • Позволяет конфигурировать scope сервиса через providedIn
  2. DI в Angular:

    • Работает через иерархию инжекторов
    • Использует различные стратегии поиска зависимостей
    • Поддерживает модификаторы разрешения зависимостей
    • Позволяет гибко управлять жизненным циклом сервисов
  3. Лучшие практики:

    • По возможности используйте providedIn: 'root'
    • Для конфигурационных значений используйте InjectionToken
    • Точно указывайте scope сервисов для оптимизации производительности