在用 Angular 做專案的時候,遇到了一個有點麻煩的問題。具體問題如下:
輪循請求某個介面,如何保證介面返回的資料與請求的順序相同?
實際的業務場景是這樣的:前端需要輪循請求後端介面獲取檔案處理進度,並在前端用進度條展示。如下方所示:
首先想到的肯定是使用 setTimeout
或者 setInterval
進行定時請求。然而結果有點詭異,進度條的變化不是遞增,而是有快有慢,比如 30%,20%,50%,40%這樣。仔細一想也知道問題出在哪,非同步請求的結果並不是按順序返回的。
我在之前的工作中還沒有遇到過這類需求,所以我並不是很清楚如果用傳統方式應該如何解決。然而很慶幸的是 RxJS 正好擅長處理這樣的問題。我立即翻了一下文件,interval
操作符可以處理定時任務,而且更強大的是返回結果也是有順序的。
interval(period: 0 = 0, scheduler: SchedulerLike = async): Observable<number>
首先看一下 interval
的說明:
建立一個可觀察物件,在規定的排程程式中,以規定的時間間隔發出連續的數值。
interval
返回一個可觀察物件,它可以週期性的發出遞增數值,但是第一次發出值是在第一個週期結束之後執行的。
以下是官方例子:
import { interval } from 'rxjs';
import { take } from 'rxjs/operators';
const numbers = interval(1000);
const takeFourNumbers = numbers.pipe(take(4));
takeFourNumbers.subscribe(x => console.log('Next: ', x));
// Logs:
// Next: 0
// Next: 1
// Next: 2
// Next: 3
不過只看官方例子還是有點懵,如果是 http 請求的話應該怎麼寫引數呢?或者說應該把 http 請求寫在哪裡?
這個地方的坑有點深,通過翻閱外文資料終於找到答案。直接上程式碼。
// 間隔 1s 請求
this.timer$ = interval(1000)
.pipe(
// 取消過時的請求值
switchMap(() => {
return this.http.get(API);
}),
)
.subscribe(
(res: any) => {
// 百分數處理邏輯
},
() => {
this.timer$.unsubscribe();
},
() => {
this.timer$.unsubscribe();
},
);
總的來說就是通過管道處理請求。最終的效果很完美。
總結
RxJS 確實是一個非常強大的工具庫,尤其處理非同步互動真的是省時省力,但是國內技術文章偏少,遇到疑難問題還需要查閱國外文章。歡迎大家評論交流。