Angular 4核心模块singleton中提供的服务是真的吗?
我试图理解angular 4中的核心模块和单例服务。 官方文件()说明了以下内容: UserService是一个应用程序范围的单例。你不想要每一个 模块具有自己的独立实例。然而,确实存在一种危险 如果SharedModule提供UserService,则不会发生这种情况 CoreModule提供用户服务。Angular注册该提供程序 使用应用程序根注入器,创建 UserService可用于任何需要它的组件,无论 组件被急切地或惰性地加载 我们建议收集这样的一次性类并隐藏它们的 核心模块内的详细信息。简化的根AppModule导入 CoreModule作为应用程序的编排器作为 全部 所以我使用提供单例服务的核心模块和构造函数Angular 4核心模块singleton中提供的服务是真的吗?,angular,ng-modules,Angular,Ng Modules,我试图理解angular 4中的核心模块和单例服务。 官方文件()说明了以下内容: UserService是一个应用程序范围的单例。你不想要每一个 模块具有自己的独立实例。然而,确实存在一种危险 如果SharedModule提供UserService,则不会发生这种情况 CoreModule提供用户服务。Angular注册该提供程序 使用应用程序根注入器,创建 UserService可用于任何需要它的组件,无论 组件被急切地或惰性地加载 我们建议收集这样的一次性类并隐藏它们的 核心模块内的详细信
constructor (@Optional() @SkipSelf() parentModule: CoreModule) { ... }
防止多次导入核心模块
1)但是,如果我在另一个模块中(例如在延迟加载模块中)提供UserService怎么办?此延迟加载的模块有一个新的服务实例?
关于forRoot方法:
@NgModule({
imports: [ CommonModule ],
providers: [ UserService ]
})
export class CoreModule {
}
static forRoot(config: UserServiceConfig): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
{provide: UserServiceConfig, useValue: config }
]
};
}
}
static forRoot(): ModuleWithProviders {
return {
ngModule: MyModule,
providers: [
MySingletonService
]
};
2) 如果我在AppModule中使用CoreModule.forRoot()导入CoreModule,UserService会发生什么情况?也有吗
谢谢,是的。这与依赖关系注入器是分层的这一事实有关
这意味着,每个模块都有一组可以注入的元素(模块级),如果其中一个元素需要一个在模块级不存在的依赖项,那么依赖项注入程序将在模块的父模块(导入它的一个模块)中查找该依赖项,依此类推,直到找到依赖项或到达根目录(app.module),如果无法解析依赖项(层次结构级别),它将在根目录中抛出错误
2) 是,将提供UserService
forRoot
将创建一个不同的CoreModule
的“版本”,其中“普通”CoreModule用您添加的额外属性展开
在大多数情况下,forRoot
将采用模块的“正常”版本,并包括提供者数组,以确保服务是单例的。模块的“正常”版本将仅包含组件、管道或其他非单音元素
以(提取的相关部分)的TranslateModule
为例:
也许这个资源可以用作进一步的解释:文档很混乱,尤其是这一行: UserService是一个应用程序范围的单例。你不想要每一个 模块具有自己的独立实例但确实存在危险 如果SharedModule提供UserService,则不会发生这种情况 如果不使用延迟加载的模块,就不会发生这种情况。让我们看一个例子。您拥有导入
B
模块的A
模块。两个模块都定义了提供程序:
@NgModule({
providers: {provide: 'b', 'b'}
})
export class BModule {}
@NgModule({
imports: [AModule]
providers: {provide: 'a', 'a'}
})
export class AModule {}
@NgModule({
providers: {provide: 'a', 'b'}
})
export class BModule {}
@NgModule({
imports: [AModule]
providers: {provide: 'a', 'a'}
})
export class AModule {}
编译器生成模块工厂时发生的情况是,它将这些提供程序合并在一起,并且只为一个模块创建工厂。下面是它的外观:
var AModuleNgFactory = jit_createNgModuleFactory0(
// reference to the module class
jit_AppModule1,
// array of bootstrap components
[jit_AppComponent2],
function (_l) {
return jit_moduleDef3([
// array of providers
jit_moduleProvideDef4(256, 'b', 'b', []),
jit_moduleProvideDef4(256, 'a', 'a', [])
...,
]);
您可以看到提供程序已合并。现在,如果您使用相同的提供程序令牌定义两个模块,则这些模块将被合并,并且来自导入另一个模块的提供程序将覆盖导入的模块提供程序:
@NgModule({
providers: {provide: 'b', 'b'}
})
export class BModule {}
@NgModule({
imports: [AModule]
providers: {provide: 'a', 'a'}
})
export class AModule {}
@NgModule({
providers: {provide: 'a', 'b'}
})
export class BModule {}
@NgModule({
imports: [AModule]
providers: {provide: 'a', 'a'}
})
export class AModule {}
工厂定义现在如下所示:
function (_l) {
return jit_moduleDef3([
// array of providers
jit_moduleProvideDef4(256, 'a', 'a', []),
...,
]);
因此,无论导入多少模块,都只会创建一个具有合并提供程序的工厂。并且只创建了一个根注入器。部件产生的喷油器不是“真实”喷油器-检查以了解原因
这个延迟加载的模块有一个新的服务实例吗
对于延迟加载的模块,Angular会为它们生成独立的工厂。这意味着它们中定义的提供者不会合并到主模块注入器中。因此,如果延迟加载的模块使用相同的令牌定义提供者,Angular将创建该服务的新实例,即使主模块中已经有一个实例
如果我在AppModule中使用CoreModule.forRoot()导入CoreModule
要了解
forRoot
的作用,请参阅。让我试着总结一下我认为学到的东西:
@NgModule({
imports: [ CommonModule ],
providers: [
UserService,
UserServiceConfig
]
})
export class CoreModule {
}
static forRoot(config: UserServiceConfig): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
{provide: UserServiceConfig, useValue: config }
]
};
}
}
当我使用forRoot方法导入模块时:
@NgModule({
imports: [ CommonModule ],
providers: [ UserService ]
})
export class CoreModule {
}
static forRoot(config: UserServiceConfig): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
{provide: UserServiceConfig, useValue: config }
]
};
}
}
static forRoot(): ModuleWithProviders {
return {
ngModule: MyModule,
providers: [
MySingletonService
]
};
- 还提供了UserService,因为(正如你们所解释的)forRoot创建了这个模块的扩展版本(它合并了服务)
- UserServiceConfig是使用forRoot方法的config参数提供的
@NgModule({
imports: [ CommonModule ],
providers: [ UserService ]
})
export class CoreModule {
}
static forRoot(config: UserServiceConfig): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
{provide: UserServiceConfig, useValue: config }
]
};
}
}
static forRoot(): ModuleWithProviders {
return {
ngModule: MyModule,
providers: [
MySingletonService
]
};
- 在appModule中只能调用forRoot一次(那么为什么按照约定该方法被称为“forRoot”)
- 如果在多个模块中导入该模块,则不会提供MySingletonService(因为它仅通过forRoot方法提供)
constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
if (parentModule) {
throw new Error(
'CoreModule is already loaded. Import it in the AppModule only');
}
}
所以在SharedModule中使用forRoot方法是有意义的,而不是在上面有特殊构造函数的模块中
因此,如果我想要应用程序范围(即使是惰性模块)的服务,我会看到两个选项: