Catch 運算子會攔截來源 Observable 的 onError
通知,並且不會將其傳遞給任何訂閱者,而是以其他項目或項目序列取代,這可能會讓產生的 Observable 正常終止或根本不終止。
Catch 運算子有多種變體,不同的 ReactiveX 實作使用各種名稱來描述此操作,如下列各節所示。
在某些 ReactiveX 實作中,有一個運算子稱為類似「OnErrorResumeNext」的名稱,其行為類似 Catch 的變體:特別是對來源 Observable 的 onError
通知做出反應。在其他實作中,有一個具有該名稱的運算子,其行為更像 Concat 的變體:無論來源 Observable 正常終止還是出現錯誤,都會執行串聯操作。這很不幸且令人困惑,但我們必須接受它。
RxClojure 將此運算子實作為 catch*
。此運算子接受兩個引數,兩者都是您選擇的函式,它們會將 onError
引發的例外狀況作為單一參數。第一個函式是述詞。如果它返回 false
,catch*
會將 onError
通知原封不動地傳遞給其訂閱者。但是,如果它返回 true
,catch*
會吞下該錯誤,呼叫第二個函式(該函式會返回 Observable),並將此新 Observable 的發射和通知傳遞給其訂閱者。
您可以將第一個函式參數(評估例外狀況的述詞)替換為表示各種例外狀況的類別物件。如果您這樣做,catch*
會將其視為等同於執行 instance?
檢查的述詞,以查看來自 onError
通知的例外狀況是否為類別物件的實例。換句話說
(->> my-observable (catch* IllegalArgumentException (fn [e] (rx/return 1))) )
等效於
(->> my-observable (catch* (fn [e] (-> instance? IllegalArgumentException e)) (fn [e] (rx/return 1))) )
RxCpp 不實作 Catch 運算子。
RxGroovy 以與 RxJava 相同的方式實作 Catch 運算子。有三個不同的運算子提供此功能
onErrorReturn
onErrorResumeNext
onExceptionResumeNext
onErrorReturn
onErrorReturn
方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,onErrorReturn
不會將該錯誤傳播給訂閱者,而是會發出指定的項目並呼叫訂閱者的 onCompleted
方法,如下列範例程式碼所示
def myObservable = Observable.create({ aSubscriber -> if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('Four'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('Three'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('Two'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('One'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onError(); }); myObservable.onErrorReturn({ return('Blastoff!'); }).subscribe( { println(it); }, // onNext { println("Error: " + it.getMessage()); }, // onError { println("Sequence complete"); } // onCompleted );
Four Three Two One Blastoff! Sequence complete
onErrorReturn(Func1)
onErrorResumeNext
onErrorResumeNext
方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,onErrorResumeNext
不會將該錯誤傳播給訂閱者,而是會開始鏡像第二個備份 Observable,如下列範例程式碼所示
def myObservable = Observable.create({ aSubscriber -> if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('Three'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('Two'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('One'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onError(); }); def myFallback = Observable.create({ aSubscriber -> if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('0'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('1'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onNext('2'); if(false == aSubscriber.isUnsubscribed()) aSubscriber.onCompleted(); }); myObservable.onErrorResumeNext(myFallback).subscribe( { println(it); }, // onNext { println("Error: " + it.getMessage()); }, // onError { println("Sequence complete"); } // onCompleted );
Three Two One 0 1 2 Sequence complete
onErrorResumeNext(Func1)
onErrorResumeNext(Observable)
onExceptionResumeNext
與 onErrorResumeNext
方法非常相似,這會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,如果傳遞給 onError
的 Throwable 是 Exception,onExceptionResumeNext
不會將該 Exception 傳播給訂閱者,而是會開始鏡像第二個備份 Observable。如果 Throwable 不是 Exception,則 onExceptionResumeNext
返回的 Observable 會將其傳播給訂閱者的 onError
方法,並且不會呼叫其備份 Observable。
onExceptionResumeNext(Observable)
RxJava 使用三個不同的運算子來實作 Catch 運算子
onErrorReturn
onErrorResumeNext
onExceptionResumeNext
onErrorReturn
onErrorReturn
方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,onErrorReturn
不會將該錯誤傳播給訂閱者,而是會發出指定的項目並呼叫訂閱者的 onCompleted
方法。
onErrorReturn(Func1)
onErrorResumeNext
onErrorResumeNext
方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,onErrorResumeNext
不會將該錯誤傳播給訂閱者,而是會開始鏡像第二個備份 Observable。
onErrorResumeNext(Func1)
onErrorResumeNext(Observable)
onExceptionResumeNext
與 onErrorResumeNext
方法非常相似,這會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,如果傳遞給 onError
的 Throwable 是 Exception,onExceptionResumeNext
不會將該 Exception 傳播給訂閱者,而是會開始鏡像第二個備份 Observable。如果 Throwable 不是 Exception,則 onExceptionResumeNext
返回的 Observable 會將其傳播給訂閱者的 onError
方法,並且不會呼叫其備份 Observable。
onExceptionResumeNext(Observable)
RxJS 使用兩個不同的運算子來實作 Catch 運算子
catch
onErrorResumeNext
catch
catch
位於下列發行版本中
rx.js
rx.all.js
rx.all.compat.js
rx.compat.js
rx.lite.js
rx.lite.compat.js
onErrorResumeNext
此實作借鑒了 Rx.NET 的混淆命名法,其中 onErrorResumeNext
會在發生錯誤和來源 Observable 正常、無錯誤終止時切換到備份 Observable。
onErrorResumeNext
位於下列發行版本中
rx.js
rx.compat.js
RxKotlin 以與 RxJava 相同的方式實作 Catch 運算子。有三個不同的運算子提供此功能
onErrorReturn
onErrorResumeNext
onExceptionResumeNext
onErrorReturn
onErrorReturn
方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,onErrorReturn
不會將該錯誤傳播給訂閱者,而是會發出指定的項目並呼叫訂閱者的 onCompleted
方法。
onErrorResumeNext
onErrorResumeNext
方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,onErrorResumeNext
不會將該錯誤傳播給訂閱者,而是會開始鏡像第二個備份 Observable。
onExceptionResumeNext
與 onErrorResumeNext
方法非常相似,這會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,如果傳遞給 onError
的 Throwable 是 Exception,onExceptionResumeNext
不會將該 Exception 傳播給訂閱者,而是會開始鏡像第二個備份 Observable。如果 Throwable 不是 Exception,則 onExceptionResumeNext
返回的 Observable 會將其傳播給訂閱者的 onError
方法,並且不會呼叫其備份 Observable。
Rx.NET 使用兩個不同的運算子來實作 Catch 運算子
Catch
OnErrorResumeNext
Catch
Catch
運算子有一個變體,可讓您指定要捕捉的 Exception 種類。如果您使用該運算子的變體,任何其他 Exception 都會像未套用 Catch
運算子一樣傳遞給訂閱者。
OnErrorResumeNext
此實作引入了一個混淆的命名法,其中儘管名稱為 OnErrorResumeNext
,但在發生錯誤和來源 Observable 正常、無錯誤終止時,都會切換到備份 Observable。因此,它更像一個串聯運算子。
RxPHP 將此運算子實作為 catch
。
使用下一個 observable 序列繼續由例外狀況終止的 observable 序列。
//from https://github.com/ReactiveX/RxPHP/blob/master/demo/catch/catch.php $obs2 = Rx\Observable::of(42); $source = \Rx\Observable::error(new Exception('Some error')) ->catch(function (Throwable $e, \Rx\Observable $sourceObs) use ($obs2) { return $obs2; }); $subscription = $source->subscribe($stdoutObserver);
Next value: 42 Complete!
RxPY 使用兩個不同的運算子來實作 Catch 運算子
catch_exception
on_error_resume_next
catch_exception
您可以將一組備份 Observable 作為個別函式參數或作為單一 Observable 陣列傳遞給 catch_exception
。如果遇到來自來源 Observable 的 onError
通知,它將訂閱並開始鏡像第一個備份 Observable。如果此備份 Observable 本身發出 onError
通知,catch_exception
會將其吞下並切換到下一個備份 Observable。如果這些 Observable 中的任何一個發出 onCompleted
通知,catch_exception
會將其傳遞並停止。
on_error_resume_next
您可以將一組備份 Observable 作為個別函式參數、作為單一 Observable 陣列或作為產生 Observable 的工廠函式傳遞給 on_error_resume_next
。當來源 Observable 終止時,無論是正常終止還是出現錯誤,on_error_resume_next
都會訂閱並開始鏡像第一個備份 Observable,然後會針對每個額外的 Observable 以遞迴方式繼續此串聯過程,直到沒有更多 Observable 可鏡像為止,屆時它會從最後一個 Observable 傳遞 onError
或 onCompleted
通知。
Rx.rb 使用兩個不同的運算子來實作 Catch 運算子
rescue_error
on_error_resume_next
rescue_error
您可以將 Observable 或產生 Observable 的工廠 action 傳遞給 rescue_error
。
on_error_resume_next
在 Rx.rb 中,on_error_resume_next
繼承了來自 Rx.NET 的誤導性命名,它會將第二個 Observable 序列附加到來源序列,無論來源序列是正常終止還是發生錯誤。
Rx.rb 使用四個不同的運算子實作 Catch 運算子
onErrorFlatMap
onError
通知,替換為來自第二個 Observable 的發射值。onErrorResumeNext
onErrorReturn
onExceptionResumeNext
onErrorFlatMap
onErrorFlatMap
處理一種特殊情況:一個來源 Observable 不符合Observable 契約,它可能會在不終止的情況下,將 onError
通知與其發射值交錯。這個運算子允許你將這些 onError
通知替換為你選擇的 Observable 的發射值,而不會取消訂閱來源,以便從來源發射的任何未來項目都將傳遞給觀察者,就好像序列沒有被 onError
通知中斷一樣。
因為 onErrorFlatMap
的設計目的是處理在發出錯誤後不會終止的病態來源 Observable,它主要用於除錯/測試場景。
請注意,你應該將 onErrorFlatMap
直接應用於病態來源 Observable,而不是在它被其他運算子修改之後的 Observable,因為這些運算子可能會在發出錯誤後立即取消訂閱來源,從而有效地重新規範來源 Observable。例如,上面的範例說明了 onErrorFlatMap
將如何響應由 Merge 運算子合併的兩個產生錯誤的 Observable
請注意,onErrorFlatMap
不會對兩個 Observable 生成的兩個錯誤都做出反應,而只會對 merge
傳遞的單個錯誤做出反應。
onErrorResumeNext
onErrorResumeNext
方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,onErrorResumeNext
不會將該錯誤傳播給訂閱者,而是會開始鏡像第二個備份 Observable。
onErrorReturn
onErrorReturn
方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,onErrorReturn
不會將該錯誤傳播給訂閱者,而是會發出指定的項目並呼叫訂閱者的 onCompleted
方法。
onExceptionResumeNext
與 onErrorResumeNext
方法非常相似,這會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError
,在這種情況下,如果傳遞給 onError
的 Throwable 是 Exception,onExceptionResumeNext
不會將該 Exception 傳播給訂閱者,而是會開始鏡像第二個備份 Observable。如果 Throwable 不是 Exception,則 onExceptionResumeNext
返回的 Observable 會將其傳播給訂閱者的 onError
方法,並且不會呼叫其備份 Observable。