【问题标题】:async factory provider and component injection in AngularAngular 中的异步工厂提供程序和组件注入
【发布时间】:2018-07-20 11:46:57
【问题描述】:

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

我有以下配置:

app.modules:

   @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;
}

有没有办法注入一个由异步工厂实例化的依赖,并且在创建组件之前解决依赖?

【问题讨论】:

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


    【解决方案1】:

    我见过的使用异步工厂的例子(例如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]
                    }
                ]
            };
        }
    }
    

    【讨论】:

    • 谢谢。此解决方案解决了组件的问题,但如果我将服务注入解析器或其他服务,则依赖项不是实例(未解析)。这是解析器构造函数中 print 的输出。 " ƒ () { console.log('Factory UsersLocalDbServices'); return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {... "
    • @CristianRinaldi 您有显示该问题的示例服务吗?
    • 是的,我做了一个“poc”,然后我上传了它,这样你就可以看到它了
    • 嗯-我想知道是不是因为您已将 TestResolver 注册为提供者,而不是作为模块上的声明...
    • 嗯,我不这么认为。我更新了“poc”,如果你运行它,你会看到初始化的顺序,它显示了依赖项是如何被注入的。 (在控制台中)
    【解决方案2】:

    有一些针对异步 DI 的努力,但它们在几年前就被放弃了。简短的回答是:异步 DI 是不可能的(使用 angular 的实现)。见https://github.com/angular/angular/issues/23279

    Mark Hughes 的回答建议返回一个 Promise 工厂。这个想法的来源是关于使用APP_INITIALIZER 令牌在引导期间执行异步操作的文章。这不是一个笼统的概念。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-18
      • 1970-01-01
      • 2020-11-18
      • 1970-01-01
      • 2014-11-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多