2017-07-19 44 views
0

我有一個服務「MyHttpService」,其包括可觀察到的是這樣的:如何在多個組件中重用角度可觀察性? (爲了避免重複的請求兩次?)

grabData() { 
return this.http.get('myaddress') 
         .map((res:Response) => {return res.json()}) 
         .catch((error:any) => Observable.throw(error.json().error || 'Server error')); 
} 

我有2個部件。 OneComponent和TwoComponent都注入了「MyHttpService」,這取決於MyHttpService返回的數據。

OneComponent首先加載。按鈕單擊後,TwoComponent加載。

內onNgInit()每個組件的我:

 this.myHttpService.grabData() 
     .subscribe(
       data => { 
// do something to the data 
}); 

它是正確的假設,即使我有這個認購的兩個組成部分,有不會是所謂的多個HTTP請求和當TwoComponent加載時,對「grabData()」的調用與OneComponent已經提取的數據相同嗎?或者它會發起一個新的呼叫?我想避免多個HTTP請求到同一個端點。如果每次調用具有此功能的組件時都進行多個調用,那麼處理此問題的最佳方法是什麼?以便每次初始化TwoComponent時都不會有多次調用該服務?

回答

3

Http服務返回所謂的冷觀察對象。這意味着每個新用戶都將導致該觀察對象的工作再次完成,在Http的情況下,將進行網絡請求。

幸運的是,RxJS中有一些機制可以讓您發佈(也稱爲多播或多路複用)觀察點,以便多個訂閱者不會導致多個請求。

我通常對Http這樣做的方法是使用.publishReplay(1).refCount()對運算符。 .publishReplay(1)意味着以後的用戶可以馬上獲得最新的成功價值,而不會提出其他請求。 .refCount()表示第一個用戶提出請求,最後一個用戶取消訂閱清理原始Http可觀察。

版本5.4.0添加了這兩個運算符的快捷方式,即.shareReplay(1)

只需在grabData()服務方法的末尾打上任一版本,它就應該像您的願望那樣工作。

grabData() { 
    return this.http.get('myaddress') 
        .map((res:Response) => {return res.json()}) 
        .catch((error:any) => 
         Observable.throw(error.json().error || 'Server error')) 
        .publishReplay(1).refCount(); // or .shareReplay(1) 
} 
+0

_和最後一個取消訂閱清理原來的Http observable._ - 正確,所以如果一些其他訂閱被做'HTTP'請求再次執行,正確?所以基本上http請求的結果將被共享,直到至少有用戶,然後請求會被重複。 'AsyncSubject'似乎是更好的選擇,你怎麼看? –

+1

@Maximux,你能分享一下AsyncSubject方法的意思嗎?基於我在使用上述方法時看到的情況,看起來像當我單擊按鈕時,客戶端使用同一個服務「grabData()」發出第二個請求,而不是使用共享/第一個「緩存」值請求。 – Rolando

1

當您在TwoComponent中訂閱時,它將導致再次發送http請求。阻止多個http調用的最好方法是將響應數據存儲在您的服務中,並在http調用之前,檢查您是否已經保存了數據,如果是,直接返回數據。

+0

我不希望downvote,但是這是要少得多習慣使用RxJS的,當網絡請求返回之前由第二訂閱不處理的情況。我試圖堅持的建議是最大限度地減少或消除手動訂閱服務中的觀察值,最好是您的組件。相反,使用運算符組合observables並使用'async'管道在視圖中使用它們。 – GregL

+1

@GregL我需要更多地深入RxJS,但我高舉了你的答案。我理解你的擔心是按照我所建議的方式進行的,並且如果有直接通過RxJS提供的方式,那肯定會是更好的選擇。 – SimplyComplexable

0

您可以使用share運算符來創建可觀察的多播。這在單個組件中也是相關的,因爲對同一個osbervable的多個異步綁定會導致多個請求。有一個很好的ng-conf談話here涵蓋了這個問題。

import 'rxjs/add/operator/share'; 

grabData() { 
    return this.http.get('myaddress') 
        .map((res:Response) => {return res.json()}) 
        .catch((error:any) => Observable.throw(error.json().error || 'Server error')) 
        .share(); 
}