web-dev-qa-db-fra.com

RxJS comment ignorer une erreur avec catch et continuer

Salut, j'ai le code suivant et je voudrais savoir comment empêcher l'observable principal (en amont) d'être supprimé lorsqu'une erreur est levée.

Comment puis-je changer le code suivant pour que tous les nombres s'attendent à ce que "4" s'affiche?

Je recherche une solution de modèle général qui fonctionnerait dans d'autres cas avec différents opérateurs. C'est le cas le plus simple que j'ai pu trouver.

const Rx = require('rxjs/Rx');

function checkValue(n) {
  if(n === 4) {
    throw new Error("Bad value");
  }
  return true;
}
const source = Rx.Observable.interval(100).take(10);

source.filter(x => checkValue(x))
  .catch(err => Rx.Observable.empty())
  .subscribe(v => console.log(v));
12
devguy

Vous souhaiterez garder la source observable en cours d'exécution, mais si vous laissez l'erreur se produire sur le flux d'événements principal, elle réduira l'intégralité de l'observable et vous ne recevrez plus d'éléments.

La solution consiste à créer un flux séparé où vous pouvez filtrer et attraper sans laisser le tuyau amont s'effondrer.

const Rx = require('rxjs/Rx');
function checkValue(n) {
  if(n === 4) {
    throw new Error("Bad value");
  }
  return true;
}
const source = Rx.Observable.interval(100).take(10);

source
  // pass the item into the projection function of the switchMap operator
  .switchMap(x => {
     // we create a new stream of just one item
     // this stream is created for every item emitted by the source observable
     return Observable.of(x)
       // now we run the filter
       .filter(checkValue)
       // we catch the error here within the projection function
       // on error this upstream pipe will collapse, but that is ok because it starts within this function and will not effect the source
       // the downstream operators will never see the error so they will also not be effect
       .catch(err => Rx.Observable.empty());
     })
     .subscribe(v => console.log(v));

Vous pouvez également utiliser le deuxième argument passé dans le sélecteur de capture pour redémarrer la source observable, mais cela le démarrera comme s'il ne s'était pas exécuté auparavant.

const Rx = require('rxjs/Rx');

function checkValue(n) {
  if(n === 4) {
    throw new Error("Bad value");
  }
  return true;
}
const source = Rx.Observable.interval(100).take(10);

source.filter(x => checkValue(x))
  .catch((err, source) => source)
  .subscribe(v => console.log(v));

Mais cela n'obtient pas l'effet souhaité. Vous verrez un flux qui émet 1..3 à plusieurs reprises jusqu'à la fin des temps ... ou vous arrêtez le script. Peu importe lequel vient en premier. (c'est essentiel ce que fait .retry())

12
Berkeley Martinez

Vous devez utiliser un opérateur flatMap où vous effectuerez le filtrage. Dans le flatMap de cet exemple, j'utilise Observable.if () pour effectuer le filtrage car il me garantit que je retourne tout le temps des observables. Je suis sûr que vous pouvez le faire autrement, mais c'est une implémentation propre pour moi.

const source = Rx.Observable.interval(100).take(10).flatMap((x)=>
    Rx.Observable.if(() => x !== 4, 
    Rx.Observable.of(x),
    Rx.Observable.throw("Bad value"))
    .catch((err) => {
        return Rx.Observable.empty()
    })
);

source.subscribe(v => console.log(v));
0
zinyando