【问题标题】:How to auto run a service from a module when it's imported in Angular?在Angular中导入模块时如何从模块自动运行服务?
【发布时间】:2019-12-13 03:53:20
【问题描述】:

我想知道如何在导入模块时从模块运行服务而无需任何手动服务注入和运行,就像 RouterModule 所做的那样。

@NgModule({
  imports: [

    BroserModule,
    MyModuleWithServicesThatShouldAutoRun,

  ]
})
export class AppModule { }

【问题讨论】:

    标签: angular typescript


    【解决方案1】:

    免责声明:这是基于another answer,其中未被接受为正确答案,因为有一种更简单、更容易的方法来完成 OP 所需的操作。

    您可以使用APP_INITIALIZER 注入令牌在任何其他应用程序代码运行之前运行初始化代码。

    APP_INITIALIZER@angular/core 中定义,您可以像这样包含它:

    import { APP_INITIALIZER } from '@angular/core';
    

    APP_INITIALIZER 是一个 OpaqueToken,它引用了 multi providerApplicationInitStatus 服务。它支持多个依赖项,您可以在您的提供程序列表中多次使用它,例如:

    @NgModule({
      providers: [
        MyService,
        {
          provide: APP_INITIALIZER,
          useFactory: (service: MyService) => function() { return service.init(); },
          deps: [MyService],
          multi: true
        }]
    })
    export class AppModule { }
    

    此提供程序声明告诉ApplicationInitStatus 类运行MyService.init() 方法。 init() 返回 PromiseApplicationInitStatus 阻止应用程序启动,直到 Promise 解决。

    export class MyService {
    
      // omitted other methods for brevity
    
      init(): Promise<any> {
    
        // start some observers, do the stuff you need
    
        // you can even request something via http
        return this.httpClient
          .get('https://someurl.com/example')
          .toPromise()
      }
    
    }
    

    这样,init 中的任何内容都会运行并阻止应用程序加载,直到 Promise 解决。

    请注意,无论init() 方法需要多长时间,这都会增加您应用的前期加载时间。要在打开路线之前加载内容,您应该改用resolver

    来源:

    【讨论】:

    • 我想调用一个异步服务,它返回一个对 observable 的订阅。所以我需要将订阅引用保存到一个变量中,以便在整个事情发生故障时取消订阅。而且我希望这不会延迟应用程序启动,因为它可以在启动时间之后运行。
    【解决方案2】:

    RouterModule 所做的是使用forRoot()forChild()(有时称为forFeature())方法,这是在加载模块时配置模块的约定。可以在here找到关于如何实现的很好的描述。

    如果你看一下RouterModule's source code,你会看到forRoot()forChild()这样配置模块:

    providers: [
            ROUTER_PROVIDERS,
            provideRoutes(routes),
            {
              provide: ROUTER_FORROOT_GUARD,
              useFactory: provideForRootGuard,
              deps: [[Router, new Optional(), new SkipSelf()]]
            },
           // many more, omitted
    ]
    

    在那个地方,您还可以添加APP_INITIALIZER,如其他答案中所述,这将有效地导致您的导入模块看起来像这样:

    @NgModule({
      imports: [
    
        BroserModule,
        MyModuleWithServicesThatShouldAutoRun.forRoot( /* some config, maybe */),
    
      ]
    })
    export class AppModule { }
    

    【讨论】:

      猜你喜欢
      • 2015-12-02
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      • 2018-08-25
      • 2019-05-14
      • 1970-01-01
      • 1970-01-01
      • 2019-05-29
      相关资源
      最近更新 更多