在 Angular 2 子模块中强制服务实例化(AngularJS 运行 块的替代方案)
Force service instantiation in Angular 2 sub-module (an alternative to AngularJS run block)
我在子模块中有一个服务,它包装了一些第三方模块,实例化并初始化其服务以准备在应用程序中使用。
@Injectable()
class SubmoduleInitializerService {
constructor (thirdPartyService: ThirdPartyService) {
thirdPartyService.initialize(...);
...
}
}
@NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService
]
})
class AppSubmodule {}
ThirdPartyService
不直接注入到应用程序中,而是被其他 ThirdPartyModule
单元使用,因此只要 SubmoduleInitializerService
注入与 ThirdPartyService
相同的注入器或父注射器,一切都很好:
export class AppComponent {
constructor(
/* DO NOT REMOVE! BAD THINGS HAPPEN! */
submoduleInitializerService: SubmoduleInitializerService
) {}
...
}
它被证明是一个糟糕的模式,因为如果 SubmoduleInitializerService
既没有在 class 中也没有在模板中使用(不小心已删除一次)。
基本上 AppSubmodule
模块需要替代 Angular 1.x angular.module(...).run(...)
块。
这里有哪些选项?
APP_INITIALIZER
(未记录)服务在 Angular2 中相当好地扮演了 AngularJS config/run 块的角色(不包括异步初始化的特性)。
对于刚刚急切实例化SubmoduleInitializerService
的noop初始化块是:
@NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService,
{
provide: APP_INITIALIZER,
useFactory: () => () => {},
deps: [SubmoduleInitializerService],
multi: true
}
]
})
class AppSubmodule {}
由于 APP_INITIALIZER
是多供应商,它允许每个应用程序有多个初始化函数,这些函数遵循模块的加载顺序。
对于同步初始化,更短(并且可能更合适)的替代方法是将服务注入模块的构造函数:
@NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService
]
})
class AppSubmodule {
constructor(sis: SubmoduleInitializerService) {}
}
如 中所述,APP_INITIALIZER
也与 config
块共享一些特征,因为它用于在组件初始化之前配置服务并且容易受到竞争条件的影响(例如,由于 APP_INITIALIZER
用于配置 Router
,因此将其注入另一个 APP_INITIALIZER
将导致循环依赖)。
我在子模块中有一个服务,它包装了一些第三方模块,实例化并初始化其服务以准备在应用程序中使用。
@Injectable()
class SubmoduleInitializerService {
constructor (thirdPartyService: ThirdPartyService) {
thirdPartyService.initialize(...);
...
}
}
@NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService
]
})
class AppSubmodule {}
ThirdPartyService
不直接注入到应用程序中,而是被其他 ThirdPartyModule
单元使用,因此只要 SubmoduleInitializerService
注入与 ThirdPartyService
相同的注入器或父注射器,一切都很好:
export class AppComponent {
constructor(
/* DO NOT REMOVE! BAD THINGS HAPPEN! */
submoduleInitializerService: SubmoduleInitializerService
) {}
...
}
它被证明是一个糟糕的模式,因为如果 SubmoduleInitializerService
既没有在 class 中也没有在模板中使用(不小心已删除一次)。
基本上 AppSubmodule
模块需要替代 Angular 1.x angular.module(...).run(...)
块。
这里有哪些选项?
APP_INITIALIZER
(未记录)服务在 Angular2 中相当好地扮演了 AngularJS config/run 块的角色(不包括异步初始化的特性)。
对于刚刚急切实例化SubmoduleInitializerService
的noop初始化块是:
@NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService,
{
provide: APP_INITIALIZER,
useFactory: () => () => {},
deps: [SubmoduleInitializerService],
multi: true
}
]
})
class AppSubmodule {}
由于 APP_INITIALIZER
是多供应商,它允许每个应用程序有多个初始化函数,这些函数遵循模块的加载顺序。
对于同步初始化,更短(并且可能更合适)的替代方法是将服务注入模块的构造函数:
@NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService
]
})
class AppSubmodule {
constructor(sis: SubmoduleInitializerService) {}
}
如 APP_INITIALIZER
也与 config
块共享一些特征,因为它用于在组件初始化之前配置服务并且容易受到竞争条件的影响(例如,由于 APP_INITIALIZER
用于配置 Router
,因此将其注入另一个 APP_INITIALIZER
将导致循环依赖)。