@Injectable() 装饰器和提供者数组

Cod*_*n25 3 dependency-injection angular-services angular-module angular

@Injectable() 装饰器中“root”中提供的服务是否仍然必须位于模块的提供者数组中?

Angular文档并没有真正给我答案,或者我不太理解它。

在我的核心文件夹中,我有一个在根目录中提供的身份验证服务。我不想将我的核心模块导入到应用程序模块中,以便使用提供的所有服务和组件。

我是否必须在模块的提供者数组中另外设置服务,或者已经使用装饰器在根级别提供该服务就足够了吗?

Kur*_*ton 7

您提供的链接中的要点是注册服务的所有不同方法,从最不具体到最具体。

应用程序特定 - 使用@Injectable({ providedIn: 'root' })

当您在根级别提供服务时,Angular 会创建 HeroService 的单个共享实例,并将其注入到任何需要它的类中。在 @Injectable() 元数据中注册提供程序还允许 Angular 通过从编译的应用程序中删除不使用的服务来优化应用程序。

特定于模块 - 在模块提供程序中注册

当您向特定 NgModule 注册提供程序时,该 NgModule 中的所有组件都可以使用同一个服务实例。要在此级别注册,请使用@NgModule()装饰器的providers属性,

组件特定 - 在组件中注册

当您在组件级别注册提供程序时,您会通过该组件的每个新实例获得该服务的一个新实例。在组件级别,在@Component()元数据的providers属性中注册服务提供者。

以上所有引用均来自官方服务和依赖注入简介页面

  • 如果你只有一个模块,那么前两种方法是等效的,只需要使用一种方法。使用@Injectable默认的 CLI 方法更容易。
  • 如果要在多个模块之间共享服务实例,请使用第一种方法。
  • 如果您希望每个独立模块都有一个实例,请使用第二种方法。
  • 如果您想要与除一个组件之外的所有组件共享应用程序范围的实例,则除了对一个异常组件使用第三种方法外,还可以使用第一种方法。

我认为大多数用例都属于前两种方法。

注册特定于模块的服务

提示:只需使用providedIn: 'root'. 如果由于树抖动而未使用模块,则不会为模块编译未使用的服务。声明特定于模块的服务似乎是多余的,并且正如我们将看到的,可能会导致问题。

有两种方法可以注册特定于模块的服务 - 从模块或从服务。

模块

@NgModule({
  providers: [MyService]
})
export class MyModule {}
Run Code Online (Sandbox Code Playgroud)

服务

@Injectable({ providedIn: MyModule })
Run Code Online (Sandbox Code Playgroud)

后者是官方推荐的方法。声明提供者数组是早期的遗留问题。

来自文档

上面的示例显示了在模块中提供服务的首选方式。此方法是首选方法,因为如果没有任何注入,它可以对服务进行树摇动。如果无法在服务中指定哪个模块应提供该服务,您还可以在模块内声明该服务的提供者

为什么你应该使用providedIn: 'root'

所以我们看到这种方法是可以摇树的。到目前为止,一切都很好。但是,如果您只是尝试导入声明使用客户端的组件的同一模块,最终会出现循环引用。

采取这样的设置:

我的模块

declarations: [
  MyComponent
]
Run Code Online (Sandbox Code Playgroud)

我的服务

@Injectable({ providedIn: MyModule })
Run Code Online (Sandbox Code Playgroud)

我的组件

constructor(private myService: MyService) {}
Run Code Online (Sandbox Code Playgroud)
  • 我的服务导入我的模块
  • 我的模块导入我的组件
  • 我的组件导入我的服务

存在循环依赖。

解决方法是创建一个服务模块并将其导入到您的模块中。

我的模块

imports: [
  MyModuleServices
],
declarations: [
  MyComponent
]
Run Code Online (Sandbox Code Playgroud)

我的模块服务


Run Code Online (Sandbox Code Playgroud)

我的服务

@Injectable({ providedIn: MyModuleServices })
Run Code Online (Sandbox Code Playgroud)

我的组件

constructor(private myService: MyService) {}
Run Code Online (Sandbox Code Playgroud)

这是一个非常冗长的替代方案,而不是简单地使用providedIn: 'root'并让 Tree Shaking 来完成工作。

  • 有趣的。除了“root”之外,我从未将“providedIn”用于任何其他用途。有趣的是,设置特定于模块的服务的官方指南是通过“providedIn: MyModule”,这相当于将服务作为提供者添加到模块中。如果您尝试对组件执行此操作,则会得到循环引用。 (2认同)