在 Angular 6 中生成服务时,提供 Injectable 装饰器的目的是啥?
Posted
技术标签:
【中文标题】在 Angular 6 中生成服务时,提供 Injectable 装饰器的目的是啥?【英文标题】:What is the purpose of providedIn with the Injectable decorator when generating Services in Angular 6?在 Angular 6 中生成服务时,提供 Injectable 装饰器的目的是什么? 【发布时间】:2018-11-23 16:37:09 【问题描述】:在 Angular CLI 中生成服务时,它会添加带有“provided in”属性的额外元数据,Injectable 装饰器的默认值为“root”。
@Injectable(
providedIn: 'root',
)
providedIn 到底是做什么的?我假设这使该服务像整个应用程序的“全局”类型单例服务一样可用,但是,在 AppModule 的提供程序数组中声明此类服务不是更干净吗?
【问题讨论】:
我认为您的更新应该是一个答案(您可以回答自己的问题),而不是添加到您的问题中。 最重要的是SINGLETON,没人提! 【参考方案1】:请参阅@Nipuna 的出色解释,
我想通过添加示例来扩展它。
如果你只是使用不带providedin
属性的 Injectable 装饰器,比如,
@Injectable()
那么您必须在相应模块的providers
数组中写入服务名称。
这样;
data.service.ts ↴
import Injectable from '@angular/core';
@Injectable()
export class DataService
constructor()
// Code . . .
app.module.ts ↴
import AppComponent from './app.component';
import DataService from './core/data.service';
@NgModule(
declarations: [AppComponent],
providers: [DataService], // ⟵ LOOK HERE WE PROVIDED IT
imports: [...],
bootstrap: [AppComponent],
)
export class AppModule
但是,如果你使用providedIn: 'root'
,像这样:
data.service.ts ↴
import Injectable from '@angular/core';
@Injectable(
providedIn: 'root',
)
export class DataService
constructor()
// Code . . .
那么我们的模块应该是这样的:
app.module.ts ↴
import AppComponent from './app.component';
import DataService from './core/data.service';
@NgModule(
declarations: [AppComponent],
providers: [],
imports: [...],
bootstrap: [AppComponent],
)
export class AppModule
请参阅我这次没有在providers
数组中添加DataService
,因为它不需要。
良好做法
这可能会派上用场,来自Angular Guides
在服务的@Injectable 装饰器中使用应用根注入器提供服务。
为什么? Angular 注入器是分层的。
为什么?当您将服务提供给根注入器时,该服务的实例是共享的,并且在需要该服务的每个类中都可用。当服务共享方法或状态时,这是理想的选择。
为什么?当您在服务的 @Injectable 装饰器中注册服务时,优化工具(例如 Angular CLI 的生产构建使用的工具)可以执行树抖动并删除未使用的服务通过您的应用。
为什么?当两个不同的组件需要不同的服务实例时,这并不理想。在这种情况下,最好在需要新的独立实例的组件级别提供服务。
【讨论】:
【参考方案2】:providedIn: 'root'
是自 Angular 6 以来提供服务的最简单、最有效的方式:
-
该服务将在应用程序范围内作为单例提供,无需将其添加到模块的提供程序数组中(如 Angular
如果服务仅在延迟加载的模块中使用,它将与该模块一起延迟加载
如果从未使用过,它将不会包含在构建中(摇动树)。
如需了解更多信息,请阅读documentation 和NgModule FAQs
顺便说一句:
-
如果您不想要应用程序范围的单例,请改用提供程序的组件数组。
如果您想限制范围以使其他开发人员永远不会在特定模块之外使用您的服务,请改用 NgModule 的
providers
数组。
【讨论】:
简单、出色、直接! 问题!我的服务肯定会依赖其他服务(通过其构造函数中的 DI)。以前,所有的依赖都将在提供服务的模块中进行管理......现在呢?特别是如果它依赖于第三方库(不使用providedIn:root),我们到底如何管理?【参考方案3】:来自文档
什么是可注入装饰器?
将一个类标记为可供 Injector 创建。
import Injectable from '@angular/core';
@Injectable(
providedIn: 'root',
)
export class UserService
服务本身是 CLI 生成的一个类,并用 @Injectable() 修饰。
providedIn 到底是做什么的?
通过将其与@NgModule 或其他InjectorType 相关联,或者通过指定应在“根”注入器中提供该注入器来确定哪些注入器将提供注入器,这将是大多数应用程序中的应用程序级注入器.
providedIn: Type<any> | 'root' | null
providedIn: 'root'
当您在根级别提供服务时,Angular 会创建一个共享的服务实例,并将其注入到任何需要它的类中。在 @Injectable() 元数据中注册提供程序还允许 Angular 通过从已编译的应用程序中删除不使用的服务来优化应用程序。
提供在:模块
还可以指定应在特定的@NgModule 中提供服务。例如,如果您不希望应用程序可以使用服务,除非它们导入您创建的模块,您可以指定应在模块中提供服务
import Injectable from '@angular/core';
import UserModule from './user.module';
@Injectable(
providedIn: UserModule,
)
export class UserService
此方法是首选方法,因为它启用了服务的 Tree-shaking(Tree-shaking 是构建过程中的一个步骤,用于从代码库中删除未使用的代码),如果没有任何东西注入它。
如果无法在服务中指定应由哪个模块提供它,您也可以在模块中为服务声明提供者:
import NgModule from '@angular/core';
import UserService from './user.service';
@NgModule(
providers: [UserService],
)
export class UserModule
【讨论】:
最好的解释。 这个答案比角度文档中的定义更好。很清楚。 解释得很好,非常感谢! 空了怎么办,比如@Injectable()
?
如果我们在 NgModule 中使用提供者,那么提供服务的价值应该是什么?【参考方案4】:
根据Documentation
:
在@Injectable() 元数据中注册提供程序还允许 Angular 通过从已编译的服务中删除服务来优化应用程序 不使用的应用程序。
【讨论】:
【参考方案5】:providedIn 告诉 Angular 根注入器负责创建服务的实例。以这种方式提供的服务会自动提供给整个应用程序使用,无需在任何模块中列出。
服务类可以充当它们自己的提供者,这就是为什么在 @Injectable 装饰器中定义它们就是您需要的全部注册。
【讨论】:
【参考方案6】:如果你使用providedIn,则注入被注册为模块的提供者,而不将其添加到模块的提供者中。
来自Docs
服务本身是 CLI 生成的一个类,它是 用@Injectable 装饰。默认情况下,此装饰器已配置 具有 providedIn 属性,该属性为服务创建提供者。 在这种情况下,providedIn: 'root' 指定服务应该是 在根注入器中提供。
【讨论】:
谢谢萨吉塔兰。好的,这听起来像是一种新的快捷方式来指定应该在哪里提供服务。我想我最初的偏好是查看模块的提供程序列表以查看所有声明为提供程序的服务,而不是仔细阅读 ProvidedIn 标记的分散代码库 .... (?) Angular 有什么理由添加这个吗?这是要解决的问题吗?我不认为这是有原因的。 保持 AppModule / CoreModule 定义更小;) @prolink007。使用 providedIn 允许应用程序延迟加载服务。要对此进行测试,请将控制台日志放入您的服务中。我的主页过去加载了 16 个服务,现在加载了 9 个。很难量化性能,但知道在需要服务之前我不会加载服务,我感觉更好:)。 您可以通过使用providedIn
属性来定义在使用@Injectable()
装饰器时应该在哪里初始化服务,从而使您的服务可摇树。然后你应该从你的NgModule
声明的providers属性以及它的import语句中删除它。这可以通过从包中删除未使用的代码来帮助减少包的大小。以上是关于在 Angular 6 中生成服务时,提供 Injectable 装饰器的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 Angular 6 中的服务将对象发送到不相关的组件?
回调在 Angular2/Firebase 中生成“TypeError:这是未定义的”
如何在自定义 Nx 生成器中生成 Angular 应用程序?