Catch

從 onError 通知中恢復,並繼續序列而不產生錯誤

Catch

Catch 運算子會攔截來源 Observable 的 onError 通知,並且不會將其傳遞給任何訂閱者,而是以其他項目或項目序列取代,這可能會讓產生的 Observable 正常終止或根本不終止。

Catch 運算子有多種變體,不同的 ReactiveX 實作使用各種名稱來描述此操作,如下列各節所示。

在某些 ReactiveX 實作中,有一個運算子稱為類似「OnErrorResumeNext」的名稱,其行為類似 Catch 的變體:特別是對來源 Observable 的 onError 通知做出反應。在其他實作中,有一個具有該名稱的運算子,其行為更像 Concat 的變體:無論來源 Observable 正常終止還是出現錯誤,都會執行串聯操作。這很不幸且令人困惑,但我們必須接受它。

另請參閱

特定語言資訊

catch*

RxClojure 將此運算子實作為 catch*。此運算子接受兩個引數,兩者都是您選擇的函式,它們會將 onError 引發的例外狀況作為單一參數。第一個函式是述詞。如果它返回 falsecatch* 會將 onError 通知原封不動地傳遞給其訂閱者。但是,如果它返回 truecatch* 會吞下該錯誤,呼叫第二個函式(該函式會返回 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
指示 Observable 在遇到錯誤時發出特定的項目,然後正常終止
onErrorResumeNext
指示 Observable 在遇到錯誤時開始發出第二個 Observable 序列
onExceptionResumeNext
指示 Observable 在遇到例外狀況(而不是其他種類的 throwable)後繼續發出項目

onErrorReturn

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

onErrorResumeNext

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

onExceptionResumeNext

onExceptionResumeNext

onErrorResumeNext 方法非常相似,這會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,如果傳遞給 onError 的 Throwable 是 Exception,onExceptionResumeNext 不會將該 Exception 傳播給訂閱者,而是會開始鏡像第二個備份 Observable。如果 Throwable 不是 Exception,則 onExceptionResumeNext 返回的 Observable 會將其傳播給訂閱者的 onError 方法,並且不會呼叫其備份 Observable。

RxJava 使用三個不同的運算子來實作 Catch 運算子

onErrorReturn
指示 Observable 在遇到錯誤時發出特定的項目,然後正常終止
onErrorResumeNext
指示 Observable 在遇到錯誤時開始發出第二個 Observable 序列
onExceptionResumeNext
指示 Observable 在遇到例外狀況(而不是其他種類的 throwable)後繼續發出項目

onErrorReturn

onErrorReturn

onErrorReturn 方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,onErrorReturn 不會將該錯誤傳播給訂閱者,而是會發出指定的項目並呼叫訂閱者的 onCompleted 方法。

onErrorResumeNext

onErrorResumeNext

onErrorResumeNext 方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,onErrorResumeNext 不會將該錯誤傳播給訂閱者,而是會開始鏡像第二個備份 Observable。

onExceptionResumeNext

onExceptionResumeNext

onErrorResumeNext 方法非常相似,這會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,如果傳遞給 onError 的 Throwable 是 Exception,onExceptionResumeNext 不會將該 Exception 傳播給訂閱者,而是會開始鏡像第二個備份 Observable。如果 Throwable 不是 Exception,則 onExceptionResumeNext 返回的 Observable 會將其傳播給訂閱者的 onError 方法,並且不會呼叫其備份 Observable。

RxJS 使用兩個不同的運算子來實作 Catch 運算子

catch
指示 Observable 在遇到錯誤時開始發出第二個 Observable 序列
onErrorResumeNext
指示 Observable 在遇到錯誤或來源 Observable 正常終止時開始發出第二個 Observable 序列

catch

catch

catch 位於下列發行版本中

  • rx.js
  • rx.all.js
  • rx.all.compat.js
  • rx.compat.js
  • rx.lite.js
  • rx.lite.compat.js

onErrorResumeNext

onErrorResumeNext

此實作借鑒了 Rx.NET 的混淆命名法,其中 onErrorResumeNext 會在發生錯誤來源 Observable 正常、無錯誤終止時切換到備份 Observable。

onErrorResumeNext 位於下列發行版本中

  • rx.js
  • rx.compat.js

RxKotlin 以與 RxJava 相同的方式實作 Catch 運算子。有三個不同的運算子提供此功能

onErrorReturn
指示 Observable 在遇到錯誤時發出特定的項目,然後正常終止
onErrorResumeNext
指示 Observable 在遇到錯誤時開始發出第二個 Observable 序列
onExceptionResumeNext
指示 Observable 在遇到例外狀況(而不是其他種類的 throwable)後繼續發出項目

onErrorReturn

onErrorReturn

onErrorReturn 方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,onErrorReturn 不會將該錯誤傳播給訂閱者,而是會發出指定的項目並呼叫訂閱者的 onCompleted 方法。

onErrorResumeNext

onErrorResumeNext

onErrorResumeNext 方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,onErrorResumeNext 不會將該錯誤傳播給訂閱者,而是會開始鏡像第二個備份 Observable。

onExceptionResumeNext

onExceptionResumeNext

onErrorResumeNext 方法非常相似,這會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,如果傳遞給 onError 的 Throwable 是 Exception,onExceptionResumeNext 不會將該 Exception 傳播給訂閱者,而是會開始鏡像第二個備份 Observable。如果 Throwable 不是 Exception,則 onExceptionResumeNext 返回的 Observable 會將其傳播給訂閱者的 onError 方法,並且不會呼叫其備份 Observable。

Rx.NET 使用兩個不同的運算子來實作 Catch 運算子

Catch
指示 Observable 在遇到錯誤時開始發出第二個 Observable 序列
OnErrorResumeNext
指示 Observable 在遇到錯誤或來源 Observable 正常終止時開始發出第二個 Observable 序列

Catch

Catch

Catch 運算子有一個變體,可讓您指定要捕捉的 Exception 種類。如果您使用該運算子的變體,任何其他 Exception 都會像未套用 Catch 運算子一樣傳遞給訂閱者。

OnErrorResumeNext

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
指示 Observable,如果遇到錯誤,則開始從一組其他 Observable 中發出項目,一次一個 Observable,直到其中一個 Observable 成功終止
on_error_resume_next
指示 Observable 串聯一組其他 Observable 發出的項目,一次一個 Observable,無論來源 Observable 或任何後續 Observable 是否以錯誤終止

catch_exception

catch_exception

您可以將一組備份 Observable 作為個別函式參數或作為單一 Observable 陣列傳遞給 catch_exception。如果遇到來自來源 Observable 的 onError 通知,它將訂閱並開始鏡像第一個備份 Observable。如果此備份 Observable 本身發出 onError 通知,catch_exception 會將其吞下並切換到下一個備份 Observable。如果這些 Observable 中的任何一個發出 onCompleted 通知,catch_exception 會將其傳遞並停止。

on_error_resume_next

on_error_resume_next

您可以將一組備份 Observable 作為個別函式參數、作為單一 Observable 陣列或作為產生 Observable 的工廠函式傳遞給 on_error_resume_next。當來源 Observable 終止時,無論是正常終止還是出現錯誤,on_error_resume_next 都會訂閱並開始鏡像第一個備份 Observable,然後會針對每個額外的 Observable 以遞迴方式繼續此串聯過程,直到沒有更多 Observable 可鏡像為止,屆時它會從最後一個 Observable 傳遞 onErroronCompleted 通知。

Rx.rb 使用兩個不同的運算子來實作 Catch 運算子

rescue_error
指示 Observable 在遇到錯誤時,開始從另一個 Observable 或從 action 返回的 Observable 發出項目
on_error_resume_next
指示 Observable 將另一個 Observable 發出的項目串聯到來源 Observable 發出的序列,無論來源 Observable 正常終止還是出現錯誤

rescue_error

rescue_error

您可以將 Observable 或產生 Observable 的工廠 action 傳遞給 rescue_error

on_error_resume_next

on_error_resume_next

在 Rx.rb 中,on_error_resume_next 繼承了來自 Rx.NET 的誤導性命名,它會將第二個 Observable 序列附加到來源序列,無論來源序列是正常終止還是發生錯誤。

Rx.rb 使用四個不同的運算子實作 Catch 運算子

onErrorFlatMap
將來自行為異常的 Observable 的所有 onError 通知,替換為來自第二個 Observable 的發射值。
onErrorResumeNext
指示 Observable 在遇到錯誤時開始發出第二個 Observable 序列
onErrorReturn
指示 Observable 在遇到錯誤時發出特定的項目,然後正常終止
onExceptionResumeNext
指示 Observable 在遇到例外狀況(而不是其他種類的 throwable)後繼續發出項目

onErrorFlatMap

onErrorFlatMap

onErrorFlatMap 處理一種特殊情況:一個來源 Observable 不符合Observable 契約,它可能會在不終止的情況下,將 onError 通知與其發射值交錯。這個運算子允許你將這些 onError 通知替換為你選擇的 Observable 的發射值,而不會取消訂閱來源,以便從來源發射的任何未來項目都將傳遞給觀察者,就好像序列沒有被 onError 通知中斷一樣。

因為 onErrorFlatMap 的設計目的是處理在發出錯誤後不會終止的病態來源 Observable,它主要用於除錯/測試場景。

unintuitive onErrorFlatMap and Merge interaction

請注意,你應該將 onErrorFlatMap 直接應用於病態來源 Observable,而不是在它被其他運算子修改之後的 Observable,因為這些運算子可能會在發出錯誤後立即取消訂閱來源,從而有效地重新規範來源 Observable。例如,上面的範例說明了 onErrorFlatMap 將如何響應由 Merge 運算子合併的兩個產生錯誤的 Observable

請注意,onErrorFlatMap 不會對兩個 Observable 生成的兩個錯誤都做出反應,而只會對 merge 傳遞的單個錯誤做出反應。

onErrorResumeNext

onErrorResumeNext

onErrorResumeNext 方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,onErrorResumeNext 不會將該錯誤傳播給訂閱者,而是會開始鏡像第二個備份 Observable。

onErrorReturn

onErrorReturn

onErrorReturn 方法會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,onErrorReturn 不會將該錯誤傳播給訂閱者,而是會發出指定的項目並呼叫訂閱者的 onCompleted 方法。

onExceptionResumeNext

onExceptionResumeNext

onErrorResumeNext 方法非常相似,這會返回一個 Observable,其行為會鏡像來源 Observable 的行為,除非該 Observable 呼叫 onError,在這種情況下,如果傳遞給 onError 的 Throwable 是 Exception,onExceptionResumeNext 不會將該 Exception 傳播給訂閱者,而是會開始鏡像第二個備份 Observable。如果 Throwable 不是 Exception,則 onExceptionResumeNext 返回的 Observable 會將其傳播給訂閱者的 onError 方法,並且不會呼叫其備份 Observable。