Final countdown. DevOps Stage 2018. Book your ticket today.
×Закрыть

Підписка на Subject RxJS і обробка помилок

Працюю з RxJS в контексті Angular applications, але покищо вистачало використовувати дуже малу частину його арсеналу — Subject, BehaviorSubject, до десятка операторів... Зараз виникла потреба обробляти помилки такого плану:

import { Subject } from 'rxjs/Subject';
import { of } from 'rxjs/observable/of';
import { catchError } from 'rxjs/operators';

const subject = new Subject<number>();
subject
  .pipe(catchError(err => of(err)))
  .subscribe(val => console.log(val));
subject.next(1);
subject.next(2);
subject.next(3);
subject.error(new Error);
subject.next(4);

Виводить:

1
2
3
Error
    // here a trace of the error

Тобто проблема в тому, що subject.next(4); не виводиться через те, що subject схопив помилку. І якщо десь у в’юхах є безпосередня підписка на Observable цього subject’а, то вона перестає працювати.

В документації Angular згадується за обробку помилок при HTTP-запитах, але цей сценарій не підходить для Observable у в’юхах, бо підписка на HTTP-запити відбувається багато разів, на відміну від підписки у в’юхах.

Хто як вирішує цю проблему?

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

У subscribe, есть второй аргумент (call back), который ожидает error

Не проблема зловити помилку, проблема щоб subject продовжував працювати після помилки. Можна, звичайно ж, ловити усі помилки і не робити еміт помилки для subject, але це більше схоже на хак, ніж на роботу за призначенням.

когда ты выкидываешь subject.error он прекращает стрим содержащийся внутри Observable и по этой причине ты не ловишь subject.next(4).
Тебе нужно не выбрасывать subject.error, а выкидывать subject.next({error: error}) и затем ловить его во втором callback твоего subscribe

Тобто ви кажете, що треба зробити так, правильно?

import { Subject } from 'rxjs/Subject';
import { of } from 'rxjs/observable/of';
import { catchError } from 'rxjs/operators';

const subject = new Subject<any>();
subject
  .pipe(catchError(err => of(err)))
  .subscribe(
    val => console.log(`val:`, val),
    err => console.log(`err:`, err)
  );
subject.next(1);
subject.next(2);
subject.next(3);
subject.next({error: new Error});
subject.next(4);

Результат виводу:

val: 1
val: 2
val: 3
val: { error: Error
    at Object.<anonymous> (/Users/kt/repos/april33/src/tmp.js:13:23)
    at Module._compile (module.js:643:30)
    at Object.Module._extensions..js (module.js:654:10)
    at Module.load (module.js:556:32)
    at tryModuleLoad (module.js:499:12)
    at Function.Module._load (module.js:491:3)
    at Function.Module.runMain (module.js:684:10)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3 }
val: 4

Тобто блок err ніколи не буде ловити помилки.

Что бы блок err ловил ошибки вам их нужно выбрасывать в pipe, метод throwError в RxJS 6, в 5 Observer.throw, сделайте ещё mergeMap в самом начале pipe и там смотрите тип объекта который приходит, если {error: error} то return Observer.throw(new Error)

Це таки хак, про який я писав вище.

Почему хак? Всегда нормальное поведение при выбрасывании ошибки приводит к остановке стрима, если вам не нужно останавливать, то вы ошибку кидаете дальше в качестве value и пишите свой обработчик который будет ее ловить

Хз... Це RxJS 5 ?
Subject хіба не закривається при виникненні помилки?
Було, здається, якесь рішення чи то з observeOn чи то з onErrorResumeNext.
P.S.
medium.com/...​ects-in-rxjs-2b08b7198b93

Подписаться на комментарии