combineLatest 使用的一个陷阱和基于 debounceTime 的解决方案
首先了解 combineLatest 這個操作符的作用:
組合多個 Observable 以創建一個 Observable,其值是根據其每個輸入 Observable 的最新值計算得出的。
其彈珠圖如下圖所示:
我們有一個限制值流和一個偏移值流。 我們使用 combineLatest 組合這些流以創建一個流,該流將在每次源流之一更改時具有一個新值。 然后我們使用 switchMap 根據這些值從后端獲取數據以獲取 pokemon$。 因為我們使用了switchMap,如果一個調用還沒有結束,那么當一個新的調用通過改變limit或者offset來發起一個新的調用時,前一個調用就會被取消。
代碼如下:
this.pokemon$ = combineLatest(limit$, offset$).pipe(map(data => ({limit: data[0], offset: data[1]})),switchMap(data => this.pokemonService.getPokemon(data.limit, data.offset)),map((response: {results: Pokemon[]}) => response.results),);代碼地址如下:
https://stackblitz.com/edit/angular-deqtkx
當我修改 limit 和 offset 為其他值之后,點擊 reset 按鈕,此時會觀察到先后發起兩個請求,并且第一個請求自動被 cancel 的情況:
通過單擊重置按鈕,我們通過同時重置限制和偏移值來更新我們的兩個源流。 這個動作的效果是 combineLatest 創建的流觸發了兩次,因此啟動了兩個后端請求,另一方面,由于我們使用了 switchMap,立即取消了一個。
我們來單步拆解,以加深印象:
- combineLatest 保存所有源流的最后一個值。比如開始場景是,limit = 8,offset = 2)
 - 單擊重置按鈕
 - limit 設置為 5
 - combineLatest 看到一個新值進入 limit 并發出一個新組合,limit = 5,offset = 2
 - switchMap 獲取這些值并訂閱觸發后端調用的流
偏移量設置為 0 - combineLatest 看到一個新的 offset 值,并發出一個新的組合,limit = 5,offset = 0
 - switchMap 獲取這些值,取消訂閱(并因此取消)先前的請求并開始新的請求
 
在此流程中您可能沒有預料到的是,無論何時設置 limit ,此更改都會在更改 offset 之前直接傳播到 combineLatest.
如何避免這個行為
如果有一種方法可以確保在同一個調用堆棧中發生的更改(這是單擊重置按鈕時發生的情況)被丟棄以支持最后一次更改,我們可以解決我們的問題。
這意味著,當 combineLatest 在同一個調用堆棧中發出兩個值時,當調用堆棧被清除時,最后一個值將被發送。
為此,我們可以在 combineLatest 之后直接利用值為 0 的 debounceTime。 這將確保只有最后一個值被傳遞給 switchMap,并且在調用堆棧被清除之后。
每當提到“在同一個調用堆棧中”時,都可以將其替換為“在事件循環的同一輪次中發生的更改”。
加上了 debounceTime(0) 之后的時序圖:
- combineLatest 保存所有源流的最后一個值,開始場景是,limit = 8,offset = 2
 - 單擊重置按鈕
 - 限制設置為 5
 - combineLatest 運算符看到一個新值進入 limit 并發出一個新組合,limit = 5,offset = 2
 - debounceTime 運算符看到一個新值,并且(因為操作符的值為 0)將等待直到調用堆棧被清除以將其傳遞
 - 偏移量設置為 0
 - combineLatest 運算符看到一個新的 offset 值,并發出一個新的組合,limit = 5,offset = 0
 - debounceTime 運算符再次看到一個新值,將丟棄舊值,并等待堆棧被清除以將其傳遞
 - 調用堆棧被清除
 - debounceTime 運算符沒有看到新的值,將通過組合,limit = 5,offset = 0 向下游發送數據
 - switchMap 操作符獲取這些值并訂閱觸發后端調用的流
 
修復代碼非常簡單,加上一行代碼即可:
debounceTime(0),
修復后的效果,點擊 reset 按鈕之后,只有一次 HTTP 請求發出了:
更多Jerry的原創文章,盡在:“汪子熙”:
 
總結
以上是生活随笔為你收集整理的combineLatest 使用的一个陷阱和基于 debounceTime 的解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: SAP 电商云 Spartacus UI
 - 下一篇: 期货高手的交易手法