RxJS continue à écouter après l'erreur Ajax

RxJs cesse d'écouter les événements de clic lorsqu'une erreur observable interne (requête Ajax). J'essaie de comprendre comment garder l'auditeur d'événements accroché à l'événement de clic de bouton et gérer gracieusement l'erreur interne d'ajax.

Voici mon code d'exemple et un lien vers plunkr

var input = $("#testBtn"); var test = Rx.Observable.fromEvent(input,'click'); var testAjax = function() { return Rx.Observable.range(0,3).then(function(x){ if(x==2)throw "RAWR"; //Simulating a promise error. return x; }); } test.map(function(){ return Rx.Observable.when(testAjax()); }) .switchLatest() .subscribe( function (x) { console.log('Next: ', x); }, function (err) { console.log('Error: ' + err); }, function () { console.log('Completed'); }); 

Http://plnkr.co/edit/NGMB7RkBbpN1ji4mfzih

Vous pouvez utiliser l'opérateur de catch (ou l'alias catchException ) pour capturer et gérer les erreurs qui se produisent dans un catchException observable, de sorte que les abonnés ne soient pas informés de l'erreur.

Ignorer les erreurs:

 return Rx.Observable .when(testAjax()) .catch(Rx.Observable.empty()); // continues with an empty obs after error. 

Manipulation des erreurs:

 var empty = Rx.Observable.return('default value'); return Rx.Observable .when(testAjax()) .catch(function (error) { console.log('error:', error); return empty; }); 

J'ai rencontré mes propres problèmes en interprétant la façon dont ce (et onErrorResumeNext ) fonctionnait. La lutte que j'ai rencontrée était avec quel contexte s'appliquait la capture (ou le résumé suivant ). La traduction colloque simple qui a du sens pour moi est la suivante:

Compte tenu d'un flux (ou observable) d'observables, catch (ou onErrorResumeNext ) consommera l'erreur et vous permettra de fournir un ou plusieurs observables pour continuer le flux d'origine avec.

La clé à emporter est que votre source d'origine est interrompue et remplacée par les observables (s) que vous fournissez dans la fonction catch / onErrorResumeNext . Cela signifie que si vous aviez quelque chose comme ça:

 var src = Rx.Observable .interval(500) .take(10) .select(function(x) { if (x == 5) { return Rx.Observable.throw('Simulated Failure'); } return Rx.Observable.return(x * 2); }) 

Ensuite, ajouter .catch(Rx.Observable.return('N/A')) ou .onErrorResumeNext(Rx.Observable.return('N/A')) ne va pas simplement continuer votre flux (fourni par l' interval ), mais Plutôt finir le flux avec un dernier observable (le N/A ).

Si vous cherchez plutôt à gérer l'échec avec grâce et à continuer le flux d'origine, vous devez alors ressembler à quelque chose comme .select(function(x) { return x.catch(Rx.Observable.return('N/A')); }) . Maintenant, votre flux remplacera tout élément observable dans le flux qui échoue avec une capture par défaut, puis continuer avec le flux source existant.

 var src = Rx.Observable .interval(500) .take(10) .select(function(x) { if (x == 5) { return Rx.Observable.throw('Simulated Failure'); } return Rx.Observable.return(x * 2); }) //.catch(Rx.Observable.return('N/A')) //.onErrorResumeNext(Rx.Observable.return('N/A')) .select(function(x) { return x.catch(Rx.Observable.return('N/A')); }) .selectMany(function(x) { return x; }); var sub = src.subscribe( function (x) { console.log(x); }, function (x) { console.log(x); }, function () { console.log('DONE'); } ); // OUTPUT: // 0 // 2 // 4 // 6 // 8 // N/A // 12 // 14 // 16 // 18 // DONE 

Voici un JSFiddle qui montre cela en action.

J'étais encore un peu confus après avoir essayé la réponse acceptée, alors c'est ce qui a fini par fonctionner pour moi. C'est ce que j'ai eu:

  Rx.Observable.fromEvent(emitter, events.SUBMIT_EVENT) .flatMapFirst(email=>{ return $.ajax({ method: "POST", url: '/email', data: { email: email }, }).promise() }) .subscribe(response=>{ if (response) { //do your success thing here } }, error =>{ //do your error thing } ) 

Lorsque le serveur a renvoyé une erreur (comme lorsque l'utilisateur a déjà entré son courrier électronique), je n'ai pas pu écouter le formulaire de courrier électronique de l'utilisateur. C'est ce qui a fonctionné pour moi:

  Rx.Observable.fromEvent(emitter, events.SUBMIT_EVENT) .flatMapFirst(email=>{ return $.ajax({ method: "POST", url: '/email', data: { email: email }, }).promise() }) .doOnError(error=> { //do your error thing here }) .retry() .subscribe(response=>{ if (response) { //do your success thing here } })