2017-10-20 63 views
0

我正在构建一个可以访问某些数据的Angular 4服务。当这个服务是第一个 实例化时,它需要建立到数据存储的连接,这是一个异步过程。Angular 4服务:我如何实现一个异步初始化进程?

我怎样才能最好地防止这种服务的消费者(即,组件或其他服务)试图使用这种异步连接过程之前,该服务已完成?

有没有什么方法可以让我的服务告诉Angular的引导程序在继续之前等待这个承诺解决?

重要的是,该服务在providers阵列中注册了我的@NgModule。所以(据我了解),Angular将构建一个服务实例,将提供给任何注入的组件或其他服务。

要明确的,这里是我害怕的场景:

  1. 在应用引导过程,角看到MyService模块的providers数组中,并调用它的构造。

  2. MyService的构造函数开始连接过程,这可能需要一两秒钟。

  3. 与此同时,Angular的引导程序不断收费,并呈现我的应用程序的仪表板。

  4. 仪表板组件注入MyService,并且(在其自己的构造函数中,或者在ngOnInit中)尝试在连接建立之前调用myService.getData()

为了说明,下面是这个服务是什么样子:

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

@Injectable() 
export class MyService { 

    private connection; 

    constructor() { 

     this.connect().then((connection) => { 
      this.connection = connection; 
      // Components should be able to consume this service once execution reaches this point, but not before! 
     }); 

    } 

    private connect(): Promise<any> { 
     // (return some promise which will eventually resolve with a connection) 
    } 

    public getData(key: string): string { 
     // (this method won't be usable until the .then() in the constructor has run) 
    } 


} 
+0

为什么不从getData()返回承诺或Observable?这可能是你必须做的,因为我猜想使用连接从数据存储区获取数据将会是异步的。 –

+0

这是一个好的想法,这可能是要做的事情。但实际上,数据访问是*不*异步(足够令人惊讶的)。所以如果有办法做我上面描述的,我更喜欢(保持数据访问逻辑更简单)。感谢这个想法。 – greenie2600

+1

我不知道在框架级别的这种情况。但是,您可以使用路由器并向父路由添加解析,以防止路由器导航到任何子路由,直到履行承诺。 –

回答

0

你需要做的是延迟初始化应用到你的连接被建立。您可以通过使用APP_INITIALIZER令牌像下面,

完全Plunker!!

onAppInit厂返回初始化承诺

export function onAppInit(svc: MyService):() => Promise<any> { 
    return svc.initialize; 
} 

的AppModule

@NgModule({ 
    imports:  [ BrowserModule ], 
    declarations: [ AppComponent ], 
    providers: [ 
    MyService, 
    { 
     provide: APP_INITIALIZER, 
     useFactory: onAppInit, 
     deps: [MyService], 
     multi: true 
    } 
    ], 
    bootstrap: [ AppComponent ] 
}) 
export class AppModule { } 

为MyService

@Injectable() 
export class MyService{ 
    connection; 

    constructor(){} 

    initialize =(): Promise<any> => { 
    return new Promise((resolve, reject) => { 
     setTimeout(() => { 
      this.connection = { 
      data : { 
       "var1": "xyz" 
      } 
      }; 
      resolve(); 
     }, 3000); 
    }); 
    } 

    getData =() => { 
    console.log(this.connection); 
    return this.connection.data; 
    } 
} 

AppComponent

@Component({ 
    selector: 'my-app', 
    template: `<h1>Hello</h1> 
    <hr /> 
    {{data | json}} 
    ` 
}) 
export class AppComponent { 
    data; 
    constructor(private svc: MyService){ } 

    ngOnInit(){ 
    this.data = this.svc.getData(); 
    } 
} 

这工作,你在你的问题问,但请注意,您的应用程序将无法呈现,直到服务被初始化,并且可能是不好的用户体验取决于可接受多少延迟

更好的解决方案是ret ü承诺或从getData()作为@JBNizet建议在评论中的Observable。

希望这有助于!