首页 文章

Angular 4核心模块,为什么有两个提供者数组

提问于
浏览
2

我正在查看有关NgModule(https://angular.io/guide/ngmodule#configure-core-services-with-coremoduleforroot)的官方角度文档,在页面末尾提供的示例中有core.module.ts文件

import { ModuleWithProviders, NgModule, Optional, SkipSelf }       from '@angular/core';
import { CommonModule }      from '@angular/common';
import { TitleComponent }    from './title.component';
import { UserService }       from './user.service';
import { UserServiceConfig } from './user.service';

@NgModule({
  imports:      [ CommonModule ],
  declarations: [ TitleComponent ],
  exports:      [ TitleComponent ],
  providers:    [ UserService ]
})
export class CoreModule {

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

  static forRoot(config: UserServiceConfig): ModuleWithProviders {
    return {
      ngModule: CoreModule,
      providers: [
        {provide: UserServiceConfig, useValue: config }
      ]
    };
  }
}

这是一个核心模块,通过使用构造函数和forRoot方法,我们确定核心模块只导入一次,并且我们只提供了一个服务实例 .

  • @NgModule()中的providers数组与forRoot方法中的providers数组有什么区别?

  • 我应该在@NgModel部分或核心模块中提供我的单件服务吗?

2 回答

  • 2

    forRoot 用于创建单例 .

    您应该只在根级别调用 forRoot() (AppModule) .

    有了这个结构:

    @NgModule({
        imports: [
            CommonModule
        ],
        declarations: [],
        exports: [],
        providers: []
    
    })
    export class I18nModule {
        static forRoot() {
            return {
                ngModule: I18nModule,
                providers: [I18nService, UserConfig]
            };
        }
    }
    

    你必须在 AppModule 中导入 I18nModule (只是一个例子):

    I18nModule.forRoot()
    

    在其他进口中像这样:

    imports: [I18nModule]
    

    基本上,在 AppModule import上,您正在实例化 forRoot() 导入模块的 providers 中的服务的单例 . 这允许您始终引用相同的实例,而不是具有相同服务的多个实例 .

    Why 2 providers arrays:

    在您的问题中,第一个数组可能完全为空,将所有提供程序添加到 forRoot() providers 数组中 . 所以你可以:

    @NgModule({
      imports:      [ CommonModule ],
      declarations: [ TitleComponent ],
      exports:      [ TitleComponent ],
      providers:    []
    })
    export class CoreModule {
    
      constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
        if (parentModule) {
          throw new Error(
            'CoreModule is already loaded. Import it in the AppModule only');
        }
      }
    
      static forRoot(config: UserServiceConfig): ModuleWithProviders {
        return {
          ngModule: CoreModule,
          providers: [
            UserService,
            {provide: UserServiceConfig, useValue: config }
          ]
        };
      }
    }
    
    • 您应该在 CoreModule 中提供单件服务,并在 AppModule 中使用 forRoot() 导入它

    • 如果您使用的是 forRoot() ,请在 forRoot 方法中添加提供商

  • 2

    这是一个核心模块,通过使用构造函数和forRoot方法,我们确定核心模块只导入一次,并且我们只提供了一个服务实例 .

    从技术上讲,它不能确保它只有一次 . 如果存在重复,构造函数将引发错误 . 解决重复错误成为开发人员的责任,有时这可能很困难 .

    @NgModule()中的providers数组与forRoot方法中的providers数组有什么区别?

    @NgModule 创建附加到 CoreModule 类的元数据 . Angular使用此元数据来加载模块 . forRoot 是一个将元数据作为数组返回的函数 . 这意味着你没有装饰器的帮助来格式化该数组并且必须手动完成 .

    forRoot 中的 providers 声明依赖关系符号与值相关联 . 该值作为参数传递给函数 .

    您实际上可以使用 @NgModule 执行此操作并获得相同的结果 .

    let config = new UserServiceConfig(); // <-- create instance here.
    
     @NgModule({
         imports:      [ CommonModule ],
         declarations: [ TitleComponent ],
         exports:      [ TitleComponent ],
         providers:    [ 
             UserService,
             {provide: UserServiceConfig, useValue: config }
         ]
     })
    

    上面的内容与_1713699相同,但它引入了两个问题 .

    • 以上代码可以多次执行

    • 模块如何知道它需要什么配置?

    我应该在@NgModel部分或核心模块中提供我的单件服务吗?

    我想说Angular中没有单身人士 . 那's because the dependency injection tree doesn' t支持提供者的这种分类 . 为了解决这个限制,我们添加了这个 forRoot 技巧,只为一个特定的导入声明一个提供者一次 .

    这是了解其工作原理的关键 . 我们不会改变所提供的内容 . 我们正在改变 imported .

    这意味着我们只需要一个模块来导入此服务 . 假设执行导入的模块仅加载一次 . 因此,这会创建该提供程序的单例 .

    重要的是你的 main 模块在它的 imports 部分调用 forRoot() ,这个函数只使用一次 .

    您阅读的教程使用此技术仅创建一个类型为 UserServiceConfig 的配置对象的提供程序 . 然后,您可以将此类型注入其他对象 .

相关问题