簡體   English   中英

如何捕獲錯誤並繼續執行 RxJs 中的序列?

[英]How to catch error and continue executing a sequence in RxJs?

我有一個要解析的項目列表,但其中一個項目的解析可能會失敗。

捕獲錯誤但繼續執行序列的“Rx-Way”是什么

代碼示例:

 var observable = Rx.Observable.from([0,1,2,3,4,5]).map( function(value){ if(value == 3){ throw new Error("Value cannot be 3"); } return value; }); observable.subscribe( function(value){ console.log("onNext " + value); }, function(error){ console.log("Error: " + error.message); }, function(){ console.log("Completed;"); });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>

我想以非 Rx 方式做的事情:

 var items = [0,1,2,3,4,5]; for (var item in items){ try{ if(item == 3){ throw new Error("Value cannot be 3"); } console.log(item); }catch(error){ console.log("Error: " + error.message); } }

我建議你改用flatMap (現在mergeMap版本 5 中的 mergeMap),如果你不關心它們,它會讓你折疊錯誤。 實際上,您將創建一個內部 Observable,如果發生錯誤,它可以被吞下。 這種方法的優點是你可以將操作符鏈接在一起,如果管道中的任何地方發生錯誤,它都會自動轉發到 catch 塊。

 const {from, iif, throwError, of, EMPTY} = rxjs; const {map, flatMap, catchError} = rxjs.operators; // A helper method to let us create arbitrary operators const {pipe} = rxjs; // Create an operator that will catch and squash errors // This returns a function of the shape of Observable<T> => Observable<R> const mapAndContinueOnError = pipe( //This will get skipped if upstream throws an error map(v => v * 2), catchError(err => { console.log("Caught Error, continuing") //Return an empty Observable which gets collapsed in the output return EMPTY; }) ) const observable = from([0, 1, 2, 3, 4, 5]).pipe( flatMap((value) => iif(() => value != 3, of(value), throwError(new Error("Value cannot be 3")) ).pipe(mapAndContinueOnError) ) ); observable.subscribe( (value) => console.log("onNext " + value), (error) => console.log("Error: " + error.message), () => console.log("Completed!") );
 <script src="https://unpkg.com/rxjs@7.0.0/dist/bundles/rxjs.umd.min.js"></script>

您需要切換到一個新的一次性流,如果其中發生錯誤將被安全處理,並保持原始流處於活動狀態:

 Rx.Observable.from([0,1,2,3,4,5]) .switchMap(value => { // This is the disposable stream! // Errors can safely occur in here without killing the original stream return Rx.Observable.of(value) .map(value => { if (value === 3) { throw new Error('Value cannot be 3'); } return value; }) .catch(error => { // You can do some fancy stuff here with errors if you like // Below we are just returning the error object to the outer stream return Rx.Observable.of(error); }); }) .map(value => { if (value instanceof Error) { // Maybe do some error handling here return `Error: ${value.message}`; } return value; }) .subscribe( (x => console.log('Success', x)), (x => console.log('Error', x)), (() => console.log('Complete')) );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>

這篇博文中有關此技術的更多信息: The Quest for Meatballs: Continue RxJS Streams When Errors Occurs

為了防止你的endlessObservable$死亡,你可以將你的failingObservable$放在一個高階映射操作符(例如switchMapconcatMapexhaustMap ...)中,並通過用一個empty() observable終止內部流而不返回任何值來吞下錯誤.

使用 RxJS 6:

endlessObservable$
    .pipe(
        switchMap(() => failingObservable$
            .pipe(
                catchError((err) => {
                    console.error(err);
                    return EMPTY;
                })
            )
        )
    );

如果您不想或無法訪問導致錯誤的內部可觀察對象,您可以執行以下操作:

使用 RxJS 7:

const numbers$ = new Subject();

numbers$
  .pipe(
    tap(value => {
      if (value === 3) {
        throw new Error('Value cannot be 3');
      }
    }),
    tap(value => {
      console.log('Value:', value);
    }),
    catchError((err, caught) => {
      console.log('Error:', err.message);
      return caught;
    })
  )
  .subscribe();

for (let n = 1; n <= 10; n++) {
  numbers$.next(n);
}

這里有趣的是可以返回的 catchError 運算符中的“捕獲”參數。 https://rxjs.dev/api/operators/catchError

它僅在源 observable 為 Hot 時有效。

就我而言,我使用 redux-observable 並且我想要一種方法來在一個地方處理我的錯誤。

我想出了這個:

const allEpics = combineEpics(
    // all my epics
);

export const rootEpic = (action$, state$, dependencies) => {
  return allEpics(action$, state$, dependencies).pipe(
    catchError((err, caught) => {
        if (err instanceof MyError) {
        return concat(of(displayAlert(err.message)), caught);
      }
      throw err;
    })
  );
};

如果我的任何史詩拋出“MyError”異常,它將被捕獲並調度另一個動作。

您實際上可以在map函數中使用try/catch來處理錯誤。 這是代碼片段

 var source = Rx.Observable.from([0, 1, 2, 3, 4, 5]) .map( function(value) { try { if (value === 3) { throw new Error("Value cannot be 3"); } return value; } catch (error) { console.log('I caught an error'); return undefined; } }) .filter(function(x) { return x !== undefined; }); source.subscribe( function(value) { console.log("onNext " + value); }, function(error) { console.log("Error: " + error.message); }, function() { console.log("Completed!"); });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM