2017-10-20 68 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。

希望這有助於!