🗂

RxJs Observable の エラーハンドリング

2022/03/11に公開

Observable の エラーハンドリング

Observable のエラーは sub.error で出力し、 subscribe の error でキャッチすることができます。

import { Observable } from 'rxjs';

const obs$ = new Observable((sub) => {
  sub.next('1');
  sub.error(new Error('something wrong'));
  console.log("after error") // this message will appear 
  sub.complete();
});

obs$.subscribe({
  next: console.log,
  error: console.error,
});

Observable のコンストラクタに渡す関数内で、sub.error のコールは関数の処理進行を妨げないので、
後続の処理はそのまま実行されますが、error を発行したタイミングで値のストリームはクローズされ、
以降で発行される sub.next の処理で流れる値は、subscribe 側で受信できません。

エラーの抑制

以下のように エラーハンドラーを記述しないような subscribe の書き方で subscribe する場合、
発生したエラーはグローバルに送出され、window の error イベントが反応します。

obs$.subscribe({
  next: console.log,
});
obs$.subscribe( console.log );

window.addEventListener('error', (event) => {
  console.log('error caught');
});

subscribe をシンプルに書きたい場合には、Observable の中でエラーを発生させないことはもちろん重要ですが、
catchError オペレータでエラーを抑制する手段も有効です。

import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';

const obs$ = new Observable((sub) => {
  sub.next('1');
  sub.error(new Error('something wrong'));
  sub.next('2');
  sub.complete();
});

obs$.pipe(
  catchError(()=>of(null)
)).subscribe(console.log);

multicast の Hot な Observable においては、
すべての subscribe が Error をハンドリングしなければ、グローバルなエラーが発行されます。

import { Observable } from 'rxjs';

const obs$ = new Observable((sub) => {
    sub.next('1');
    sub.error(new Error('something wrong'));
    console.log('hoge');
    sub.complete();
});

const sub = new Subject();

sub.subscribe(console.error); // global error here 
sub.subscribe({
    error: console.log,
});
obs$.subscribe(sub);

エラーハンドリングの実装例

API のエラー処理

API の結果などは catchError で以下のように処理しておくと利用側での扱いが楽になります。

const user$ = this.userService.getProfile().pipe(
  catchError(e => {e})  
)

テンプレート側でのエラーの有無は以下のように ngIf が実装可能です。

<div *ngIf="(user$ | async).e">
</div>  

Discussion