Для чего нужен providedIn в декораторе Injectable при создании сервисов в Angular 6?
Что такое providedIn и зачем он нужен?
providedIn — это опция декоратора @Injectable, появившаяся в Angular 6. Она позволяет указать, на каком уровне инжектор должен создать и предоставить экземпляр вашего сервиса. Раньше вы регистрировали сервис вручную в массиве providers модуля. Теперь Angular может сделать это автоматически, причём с дополнительными преимуществами.
1. providedIn: 'root' — что это значит?
providedIn: 'root' означает, что сервис будет зарегистрирован в корневом инжекторе приложения. Это самый распространённый вариант. Он делает сервис доступным во всём приложении (во всех модулях, компонентах, директивах и других сервисах) как синглтон — один экземпляр на всё приложение.
Важно: если вы указали providedIn: 'root', вам НЕ НУЖНО добавлять этот сервис в providers модуля. Если вы сделаете и то, и другое, ничего страшного не произойдёт — Angular просто проигнорирует дублирование, но лучше так не делать, чтобы избежать путаницы.
2. providedIn: SomeModule — что это?
Вы можете указать конкретный модуль, например:
@Injectable({
providedIn: AdminModule
})
export class AdminService { }
В этом случае сервис будет зарегистрирован в инжекторе модуля AdminModule. Он будет доступен только внутри этого модуля (и его дочерних компонентов/сервисов). Если AdminModule будет лениво загружаться (lazy-loaded), то сервис будет создан только при загрузке этого модуля. Это позволяет экономить память и ресурсы: если модуль никогда не загрузится, сервис не будет создан.
3. Влияние на производительность и синглтон
Синглтон: при providedIn: 'root' сервис — гарантированный синглтон. При регистрации в модуле тоже получается синглтон, но с одним важным нюансом: если один и тот же сервис зарегистрировать в двух разных лениво загружаемых модулях, то каждый модуль получит свой собственный экземпляр. С providedIn: 'root' такого не случится — всегда будет один экземпляр.
Производительность и tree-shaking: это главное преимущество providedIn. Если вы регистрируете сервис в модуле, Angular не может "знать", используется ли сервис на самом деле. Даже если вы нигде не внедряете сервис, он всё равно будет включён в финальную сборку (bundle). С providedIn: 'root' Angular использует технику tree-shaking: если сервис нигде не используется (ни в одном компоненте или другом сервисе), он будет автоматически исключён из финальной сборки. Это уменьшает размер приложения.
4. Практические рекомендации
- Всегда используйте
providedIn: 'root'для сервисов, которые должны быть доступны глобально (например, сервисы данных, авторизации, логирования). - Если сервис нужен только в одном конкретном модуле (особенно лениво загружаемом), укажите
providedIn: ModuleName. - Не регистрируйте сервис одновременно и через
providedIn, и вprovidersмодуля — это избыточно. - Для компонентных сервисов (которые должны жить только внутри одного компонента) продолжайте использовать
providersв декораторе@Component.
Итоговый пример
// Глобальный сервис — доступен везде
@Injectable({
providedIn: 'root'
})
export class GlobalService {
getData() { return 'global data'; }
}
// Сервис для лениво загружаемого модуля
@Injectable({
providedIn: AdminModule
})
export class AdminService {
getAdminData() { return 'admin data'; }
}
// Сервис для конкретного компонента
@Component({
selector: 'app-user',
template: '...',
providers: [UserService] // только для этого компонента и его детей
})
export class UserComponent {
constructor(private userService: UserService) { }
}
Таким образом, providedIn — это современный, более эффективный и удобный способ регистрации сервисов. Он делает код чище, уменьшает размер сборки и даёт больше контроля над областью видимости сервиса.
Дополнение: providedIn и ленивая загрузка (Lazy Loading)
Коллега выше отлично объяснил основы. Я хочу добавить важный нюанс про ленивую загрузку модулей, который часто вызывает путаницу.
Если у вас есть лениво загружаемый модуль (например, AdminModule), и вы зарегистрировали сервис через providedIn: AdminModule, то этот сервис НЕ БУДЕТ доступен в корневом инжекторе. Это значит, что если какой-то сервис из другого модуля (не из AdminModule) попытается внедрить AdminService, Angular выбросит ошибку. Это логично: зачем создавать сервис для админки, если пользователь даже не заходил в админку?
Однако есть хитрость: если вы укажете providedIn: 'root' для сервиса, который используется только в лениво загружаемом модуле, то сервис всё равно будет создан при старте приложения (потому что корневой инжектор создаётся сразу). Это может быть неэффективно, если сервис тяжёлый. Поэтому правило такое:
- Сервис нужен везде и сразу →
providedIn: 'root' - Сервис нужен только внутри лениво загружаемого модуля →
providedIn: ModuleName - Сервис нужен в нескольких модулях, но не во всех → создайте отдельный shared-модуль и зарегистрируйте сервис в его
providers(старый способ). Либо, начиная с Angular 14, можно использоватьprovidedIn: 'platform'для сервисов, которые должны жить дольше, чем само приложение (редкий случай).
Также помните: если вы используете providedIn: SomeModule, этот модуль должен быть импортирован в ваше приложение (или в другой модуль, который его импортирует). Иначе Angular не сможет найти инжектор для этого сервиса.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги