[Angular 進階議題]使用shareReplay operator避免ajax時async pipe重複發request的問題

Angular內建了一個async pipe,讓我們在view中處理非同步資料時更加輕鬆,不論是Promise還是Observable都不需要額外做then或subscribe的動作,只要在view中加入async這個pipe就可以自動把該做的事情都做好,但當當一個非同步的結果會在不同地方顯示時,用async pipe就會發生重複處理的問題,這時就可以搭配RxJs的shareReplay operator來解決這個問題。

假設我們有個非同步的程式如下:

 ngOnInit() {
   this.data$ = this._simulateRequest();
 }

 private _simulateRequest(): Observable <any>{
   return Observable.create((observer: Observer<any>) => {
     console.log('模擬request發生了...');
     observer.next({ foo: 'bar' });
     observer.complete();
   });
 }

```</any></any> 

接著view的內容為:

```html

# 第一次request

 {{ data$ | async | json}}

# 第二次request

 {{ data$ | async | json}}

# 第三次request

 {{ data$ | async | json}}

跑出來的結果如下圖:

這個結果非常好理解,因為async pipe本來就是幫我們去做subscribe的動作,每次subscribe就會去執行Observer.create()裡面的內容,不過當我們資料是透過ajax呼叫時,就必須呼叫3次,這樣可能會造成一些不必要的網路資源浪費。

當然最簡單的方式是透過自己subscribe一次後把資料放到一個變數中,而不再去使用async pipe:

   this._simulateRequest().subscribe(returnData => {
     this.data = returnData;
   });

但這樣總是感覺醜了一點,不過好加在RxJs提供了大量的operators來解決各式各樣的難題,我們可以利用shareReplay(N)來“重播”最近N次的節果,以一般ajax來說只會發生一次就complete了,所以裡面參數有沒有設定都沒關係,把原來request的程式稍微改寫一下:

this.data$ = this._simulateRequest().shareReplay();

就不會發生重複request的結果啦!

果然RxJs玩到後來就是比誰會的operators多啊XD

程式碼範例:https://github.com/wellwind/angular-advanced-topic-demo/tree/master/using-share-operator

如果您覺得我的文章有幫助,歡迎免費成為 LikeCoin 會員,幫我的文章拍手 5 次表示支持!
[Angular 進階議題]fakeAsync/tick-在Angular中測試非同步程式的時光魔術師!
[Angular 進階議題]Karma + Jasmine跑測試太慢?試試看Jest吧!

有任何問題或建議嗎?歡迎留言給我

文章大綱