Angular中的异步工厂提供程序和组件注入

时间:2018-07-20 11:46:57

标签: angular asynchronous dependency-injection async-await factory

我在注入由异步工厂提供程序创建的依赖项时遇到问题。

我有以下配置:

应用程序模块:

   @NgModule({
   declarations: [       
      ...
      ...,
   imports: [
        BrowserModule,
        BrowserAnimationsModule,
        FormsModule,
        HttpModule,
        HttpClientModule,
        ...
        UsersModule.forRoot(),
        ...
        APP_ROUTERS
    ]
    })
    export class AppModule {}

APP_ROUTERS

const rootRouters = [
   {path: '', redirectTo: 'tests', pathMatch: 'full'},
   {
       path: 'users/login',
       component: SUserLoginComponent,
       resolve: {
          localUsers: UsersLocalResolver
       },
   },

   {
       path: '',
       loadChildren: 'app/test/test.module#TestModule',
       canActivate: [SecurityAuthenticationGuard],
       data: {
          preload: true
       }
   },

];
export const APP_ROUTERS: ModuleWithProviders = RouterModule.forRoot(rootRouters, {onSameUrlNavigation: 'reload'});

user.modules

@NgModule({
    imports: [
        CommonModule,
        ...
    ],
    declarations: [
        SUserLoginComponent,
    ],
    exports: [
        SUserLoginComponent
    ]
})
export class UsersModule {
    static forRoot(): ModuleWithProviders {
        return {
            ngModule: UsersModule,
            providers: [

                UsersLocalResolver,
                {
                  provide: UsersLocalDbServices,
                  useFactory: (dbservice: IndexedDBService): Promise<UsersLocalDbServices> => {
                    console.log('Factory UsersLocalDbServices');
                    return new Promise<UsersLocalDbServices>(async (resolve) => {
                        if (dbservice.getVersion() === null) {
                            await dbservice.open(LOCAL_DATABASE_NAME);
                        }
                        const instance = new UsersLocalDbServices(dbservice);
                        const result = await instance.setup();
                        resolve(instance);
                    });
                },
                    deps: [IndexedDBService]
                }
            ]
        };
    }
}

使用异步工厂的服务(UsersLocalDbServices)被注入到 SUserLoginComponent 组件中,但是在实例化该组件之后将对其进行解析。 如何做到这一点,以便实例在创建组件时就存在?

export class SUserLoginComponent implements OnInit, AfterViewInit {

  constructor(private router: Router,
                private activatedRoute: ActivatedRoute,
                private db: IndexedDBService,
                private securityServices: SecurityServices,
                private usersLocalDbService: UsersLocalDbServices) {
    }
}

问题在于“ usersLocalDbService”是一个承诺,而不是服务实例。

我已经通过执行以下操作解决了这个问题,但事实是它太可怕了:

async ngOnInit() {
    this.usersLocalDbService = await this.usersLocalDbService;
}

是否有任何方法可以注入由异步工厂实例化的依赖关系,并在创建组件之前解决该依赖关系?

2 个答案:

答案 0 :(得分:0)

我所看到的使用异步工厂的示例(例如https://juristr.com/blog/2018/01/ng-app-runtime-config/#runtime-configuration)似乎使用了一个函数,该函数返回的函数返回一个Promise,而不是直接返回一个Promise。

将其应用于您的模块会得到:

export class UsersModule {
    static forRoot(): ModuleWithProviders {
        return {
            ngModule: UsersModule,
            providers: [

                UsersLocalResolver,
                {
                  provide: UsersLocalDbServices,
                  useFactory: (dbservice: IndexedDBService) => {
                    return () => {
                        console.log('Factory UsersLocalDbServices');
                        return new Promise<UsersLocalDbServices>(async (resolve) => {
                            if (dbservice.getVersion() === null) {
                                await dbservice.open(LOCAL_DATABASE_NAME);
                            }
                            const instance = new UsersLocalDbServices(dbservice);
                            const result = await instance.setup();
                            resolve(instance);
                        });
                    }
                },
                    deps: [IndexedDBService]
                }
            ]
        };
    }
}

答案 1 :(得分:0)

为异步DI做出了一些努力,但几年前已放弃。简短的答案是:异步DI是不可能的(使用angular的实现)。参见https://github.com/angular/angular/issues/23279

Mark Hughes的答案建议返回Promise工厂。该想法的源头是有关在引导过程中使用APP_INITIALIZER令牌执行异步操作的。这不是一个普遍的概念。