NgModule 导入服务时,应该导入 "imports" 数组还是 providers 数组?

When import services, should I import them in "imports" array or providers array in NgModule?

来自 Angular 文档,NgModule 中关于 imports 的定义是:

Specifies a list of modules whose exported directives/pipes should be available to templates in this module.

providers

Defines the set of injectable objects that are available in the injector of this module.

所以问题来了,当我想使用第 3 个模块中的第 3 个服务时,我应该在 imports 中导入模块,还是在 providers 中注册特定服务?

when I want to use a 3rd service packed in a 3rd module, should I import the module in "imports", or register the particular service, in "providers"?

您可以导入提供服务的模块。

一般来说,添加到任何模块的提供程序数组的所有服务都是应用程序范围的单例 - 这意味着它们会自动添加到根注入器。无需将它们显式添加到 AppModule 的 providers 数组中。

这意味着当您导入一个模块(或另一个模块导入一个模块)并填充了 providers 数组时,它们提供的服务可以注入到任何可注入的构造函数中——无论它在哪里。只需导入服务,并将其添加到可注入的构造函数中。

现在,我说 "in general" 因为在大多数情况下这是真的。唯一不同的情况是模块是延迟加载模块(即加载延迟加载的路由)。延迟加载的模块有自己的根作用域。如果您将其视为例外,那一切都说得通。

所以回答你的问题:

  1. 如果有这种方法就推荐module.forRoot()。这个 returns 一个带有服务的模块,它将被根注入器引导。

    @NgModule({
        // forRoot ensures that services are added to root injector
        imports: [ThirdPartyModule.forRoot()],
        exports: [],
        declarations: [...],
        providers: [],
    })
    export class AppModule{ }
    
  2. 如果没有"forRoot"方法,那么直接将模块导入AppModule即可。很可能,该模块具有旨在向根注入器注册的服务。

    @NgModule({
        imports: [ThirdPartyModule],
        exports: [],
        declarations: [...],
        providers: [],
    })
    export class AppModule{ }
    
  3. 如果您需要从 FeatureModule(或 SharedModule)导入模块,因为您想要利用其中包含的组件、指令和管道,您应该使用 forChild()方法,如果有的话。

    @NgModule({
        // does not include any services. You still need to import
        // .forRoot() in the AppModule
        imports: [ThirdPartyModule.forChild()],
        exports: [],
        declarations: [...],
        providers: [],
    })
    export class FeatureModule { }
    
  4. 如果模块的作者没有提供 forRoot()forChild() 方法,可能是它从未打算被 AppModule 以外的任何模块导入.

  5. 模块的作者可能已决定在模块中包含服务,但默认情况下选择不将其添加到提供者数组中。在这种情况下,您可以将它添加到模块的提供程序数组(服务将具有根范围),或将其添加到组件的提供程序数组(服务将具有组件范围)。

创建一个 shared/core 模块并将所有公共模块包含在该模块的提供程序数组中,并在需要时导入该模块。
否则最好只包含服务而不是整个模块。它只是用例。

import {
  ModuleWithProviders, NgModule,
  Optional, SkipSelf
} from '@angular/core';
import { CommonModule } from '@angular/common';

import { SharedService, AuthenticationService, AuthBlockService, LocalStorageService } from './services/index';
@NgModule({
  imports: [CommonModule],
  providers: [SharedService, AuthenticationService, LocalStorageService, AuthBlockService]
})
export class CoreModule {

  constructor( @Optional() @SkipSelf() parentModule: CoreModule) {
    if (parentModule) {
      throw new Error(
        'CoreModule is already loaded. Import it in the AppModule only');
    }
  }


}

and use this core modules in the root modules inside imports array.