前言
前幾篇介紹過了
這篇繼續介紹 Error Handling Operators.
參考
RxJS 錯誤處理 Operators (1) - catchError / finalize / retry / retryWhen
Docs – Error Handling Operators
Observable and Subscriber Handler Error
Observable 的流程是 : Observable init > pipe > subscribe
不經過 pipe 的情況下, 處理 error 的方式如下:
const obs = new Observable(subscriber => { subscriber.error('error message'); // throw 'error message'; // throw 也是可以 }); obs.subscribe({ error: errorMessage => console.log(errorMessage), // error message });
簡單明瞭.
catchError
catchError 是 pipe 階段的 error handle. 它是 operator 來的.
catch error and change to succeeded
const obs = new Observable(subscriber => { subscriber.error('error message'); }); obs .pipe( catchError(error => { console.log(error); // error message return of('succeeded'); }) ) .subscribe({ next: value => console.log(value), // succeeded error: errorMessage => console.log(errorMessage), // won't call });
catchError 接收到 error 後, 可以有幾個處理方式. 上面這個是返回一個 "成功" 的 Observable, 這樣 error 就不會在傳下去了.
catch error and re-throw
catch error 然後繼續往下 throw error,
throwError 方法之前介紹過了, 它是 Creation Operators 的一員.
catchError(error => { return throwError(() => 're-throw error'); // throw 're-throw error'; // 用 throw 也可以 })
小結
總之, catchError 要返回一個 Observable, 可以是 succeeded 或者是 error
catchError(error => { if (Math.random() < 0.5) { return throwError(() => 're-throw error'); // throw 're-throw error'; // 用 throw 也可以 } else { return of('succeeded'); } })
catch error and retry
除了 succeeded 和 error, 還有一種處理方式是 retry. 所謂 retry 就是 unsubscribe 當前的 stream, 重新 subscribe Observable 得到新的 stream (舊的 Observable 會 displose, 新的會 init)
catchError((error, caught) => { return caught; })
返回 catchError 的第二個參數 caught 就表示要 retry. retry 可能會導致死循環的哦.
所以必須要有條件, 避開死循環, 比如:
catchError((error, caught) => { if (Math.random() < 0.5) { return caught; // retry } else { return of('succeeded'); } })
delay retry
catchError((error, caught) => { return timer(2000).pipe(switchMap(() => caught)); })
返回一個 delay 的 Observable 就可以延後 retry 了. 這裏用了 switchMap 把 timer 的值換成了 caught observable. (這個 operator 我還沒有介紹過的)
retry count
要計算 count 只能開一個外部的 variable 做記入. 或者封裝一個自定義 operator. 但更簡單的方法是直接用 RxJS 提供的 retry 和 retryWhen operator. 下面會介紹.
retry
用 catchError + caught 實現 retyr 太費勁了, 所以 RxJS 封裝了 retry operator
retry({ count: 3, delay: 2000, resetOnSuccess: false, })
count 聲明可以 retry 多少次
delay 聲明 retry 的間隔時間, 有時候 error 是因爲 server 繁忙, 只要等 1,2 秒在 retry 發 ajax 就可以解決了.
此外 delay 還支持更復雜的 config. 通過判斷 error 和 retryCount 來決定要 delay 多少秒.
我們甚至可以返回 click$ 讓 user 點擊觸發 retry.
也可以直接返回 throwError 結束 retry (即便還沒有 hit 到 max retry count), 靈活就對了
delay: (error, retryCount) => timer(2000 * retryCount)
resetOnSuccess 聲明當 retry 成功以後是否要 reset retry count. 默認值是 false, 通常 reset 是正確的, 所以一般我都是 set 成 true.
retryWhen
已經廢棄了, 改用 retry + delay option 實現吧.
一句話總結
catchError : 在 pipe 中 catch error, 3中處理, 成功, 繼續 error, retry
retry : 用 catchError 做 retry 太費勁就有了 retry operator
retryWhen : 廢棄了, 改用 retry + delay option 實現.