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();
});
}
接著view的內容為:
<h1>第一次request</h1>
<pre>
{{ data$ | async | json}}
</pre>
<h1>第二次request</h1>
<pre>
{{ data$ | async | json}}
</pre>
<h1>第三次request</h1>
<pre>
{{ data$ | async | json}}
</pre>
跑出來的結果如下圖:
這個結果非常好理解,因為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