javascript - Ako vyvolám chybu na behaviour subject a pokračujem v toku?
Na jednom konci mám stream, ktorý môže príležitostne vyhodiť chybu:
this.behaviorSubject.error(error)
Neskôr však chcem pokračovať v streamovaní:
this.behaviorSubject.next(anotherValue)
Na druhej strane mám odberateľa prihláseného na behaviorSubject.asObservable().
V odbere sa zaoberám hodnotou a chybou:
.subscribe(
( value ) => { /* ok */ },
( error ) => { /* some error */ }
);
Chcem, aby efekt bol rovnaký ako jednoduchý onSuccess a onError callback, kde onError sa volá vždy, keď nastane chyba, a nebráni budúcim volaniam onSuccess. Ako to urobiť s RXJS?
Pozrel som sa na catch, ale zdá sa, že len zabraňuje, aby sa volala chyba na odberateľoch.
Odpoveď č. 1
Krátka odpoveď: Nie je to možné.
Ako s tým pracovať: Základný koncept RxJS je taký, že akékoľvek volanie error alebo complete v podstate "zabije" dátový tok. Tento koncept vás núti nielen "nahádzať chyby sem a tam podľa vlastného uváženia", ale správne spracovávať chyby a tok dát vo vašej aplikácii. Napríklad BehaviorSubject je typicky určený na uchovávanie dát, avšak nemal by sa používať aj na proces získavania/vytvárania týchto dát a spracovávanie možných chýb, ktoré môžu vzniknúť počas získavania dát.
Takže ak chcete postupovať podľa pravidiel, mali by ste rozdeliť svoj tok na dve časti:
- Vyhľadávanie/vytváranie údajov: Stream, ktorý sa spustí raz, potom ho dokončí a/alebo vyvolá chybu, keď niektorá nastane. Keď sa údaje získajú, budú odoslané do úložiska.
- Obchod (napr. vo vašom prípade: množstvo BehaviorSubjects): Do obchodu prichádzajú iba platné údaje, čo znamená, že tu sa nevykonáva žiadne spracovanie chýb a všetky časti, ktoré závisia od obchodu, môžu dôverovať obchodu, že obsahuje správne údaje.
Ako príklad môže váš tok údajov vyzerať nasledovne (ako hrubý náčrt):
store.ts
dataStore: BehaviorSubject<IData> = new BehaviorSubject<IData>();
errorMessage: BehaviorSubject<IErrorMsg> = new BehaviorSubject<IErrorMsg>();
data-retrieval.ts
fetchDataById(id: string) {
httpService.get(`some/rest/endpoint/${id}`)
.subscribe(handleData, handleError);
}
handleData(data: IData) {
errorMessage.next(null);
dataStore.next(data);
}
handleError(error: Error) {
errorMessage.next(error.message);
dataStore.next(null);
}
"Ale toto vyzerá ako veľa režie..." - Pravda, avšak zabezpečuje to čistý a ľahko pochopiteľný tok dát vo vašej aplikácii, ktorý je jednoduché testovať a udržiavať. Existujú tiež hotové koncepty ukladania ako ngrx alebo redux, ktoré je možné použiť.
Odpoveď č. 2
Rx je v podstate postavený na koncepte, že observable je buď aktívny, alebo ukončený (onComplete alebo onError). Keď sa Observable ukončuje, odhlási sa zo svojho upstream Observable. Žiadny .catch nemôže tento správanie opraviť, len vám dáva možnosť namapovať chybu na niečo iné.
Rx.Observable.interval(500)
.mergeMap(i => i % 3 == 2 ? Rx.Observable.throw(new Error('kboom')) : Rx.Observable.of(i))
.catch(err => Rx.Observable.of(err.message))
.subscribe(
val => console.log('val: ' + val),
err => console.log('err: ' + err),
() => console.log('stream completed')
)
Všimnite si, že tento príklad sa dokončí po 3 emisiách namiesto 5
Keď vyvoláte this.behaviorSubject.error(error), interné to ukončí Observable obsiahnutý vo vašom Subject. Ak chcete nejako vysielať chyby, potom musíte urobiť, aby vaše chyby boli hodnoty, ktoré nie sú chybami:
this.behaviorSubject.next({ value: 'somevalue' });
this.behaviorSubject.next({ error: error });
this.behaviorSubject.next({ value: 'somevalue' });
Potom ste schopní rozlíšiť na základe vlastností vašej emitovanej hodnoty, aké opatrenie by ste mali podniknúť.
