Angular单例StoreService多次创建问题及解决方案咨询
我的应用包含多个模块:AssetModule提供StoreService(Injectable,由模块提供),DashboardModule和MapModule均导入AssetModule并引用StoreService。使用下方路由配置切换模块时,尽管StoreService应为单例,却每次都会被创建;懒加载模块时问题更严重,每次路由到对应模块都会创建新实例,且旧实例的OnDestroy不会触发,导致订阅的observables/emitters事件会在所有废弃实例上触发。如何避免该行为?
路由配置:
export const routes: Routes = [ { path: '', loadChildren: () => DashboardModule, canActivate: [LoginAllRoutesGuard] }, { path: 'asset', loadChildren: () => AssetModule, canActivate: [LoginAllRoutesGuard] }, { path: 'map', loadChildren: () => MapModule, canActivate: [LoginAllRoutesGuard] }, ];
解决方案
1. 直接将服务配置为全局单例(推荐)
修改StoreService的@Injectable装饰器,使用providedIn: 'root',让Angular自动在根注入器中提供该服务,确保整个应用只有一个实例:
@Injectable({ providedIn: 'root' // 全局根注入器提供,保证单例 }) export class StoreService { // ... 服务逻辑 }
同时移除AssetModule的providers数组中对StoreService的声明,避免模块级别的重复提供。
2. 使用forRoot()模式确保模块单例
如果必须通过AssetModule提供服务,可以给AssetModule添加forRoot()静态方法,仅在根模块中调用该方法导入,其他功能模块直接导入AssetModule本身:
改造AssetModule:
@NgModule({ // 声明、导入、导出等配置,不要在providers中添加StoreService }) export class AssetModule { static forRoot(): ModuleWithProviders<AssetModule> { return { ngModule: AssetModule, providers: [StoreService] // 仅在forRoot时提供服务 }; } }
在根模块(通常是AppModule)中导入:
@NgModule({ imports: [ BrowserModule, RouterModule.forRoot(routes), AssetModule.forRoot() // 根模块调用forRoot,确保服务单例 ] }) export class AppModule {}
DashboardModule和MapModule中正常导入AssetModule即可:
@NgModule({ imports: [AssetModule] }) export class DashboardModule {}
3. 修复懒加载模块的重复导入问题
当前路由将AssetModule作为独立懒加载模块加载,每次路由到/asset都会创建新的AssetModule实例,进而生成新的StoreService。需要调整路由配置:不要将AssetModule作为独立路由模块懒加载,而是让它作为共享模块被其他懒加载模块导入,或者整合AssetModule的功能到其他模块中。
内容的提问来源于stack exchange,提问作者Patola

