J'ai une liste d'éléments à analyser, mais l'analyse de l'un d'entre eux peut échouer.
Quel est le "Rx-Way" pour attraper l'erreur mais continuer à exécuter la séquence
Exemple de code:
var observable = Rx.Observable.from([0,1,2,3,4,5])
.map(
function(value){
if(value == 3){
throw new Error("Value cannot be 3");
}
return value;
});
observable.subscribe(
function(value){
console.log("onNext " + value);
},
function(error){
console.log("Error: " + error.message);
},
function(){
console.log("Completed!");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>
Ce que je veux faire d'une manière non-Rx-Way:
var items = [0,1,2,3,4,5];
for (var item in items){
try{
if(item == 3){
throw new Error("Value cannot be 3");
}
console.log(item);
}catch(error){
console.log("Error: " + error.message);
}
}
Merci d'avance
Je suggérerais que vous utilisiez plutôt flatMap
(maintenant mergeMap
dans la version 5 de rxjs), ce qui vous permettra de réduire les erreurs si vous ne vous en souciez pas. Effectivement, vous allez créer un observable interne qui peut être avalé en cas d'erreur. L'avantage de cette approche est que vous pouvez chaîner des opérateurs. Si une erreur se produit n'importe où dans le pipeline, elle sera automatiquement transmise au bloc d'interception.
var observable = Rx.Observable.from([0, 1, 2, 3, 4, 5])
.flatMap((value) =>
Rx.Observable.if(() => value != 3,
Rx.Observable.just(value),
Rx.Observable.throw(new Error("Value cannot be 3")))
//This will get skipped if upstream throws an error
.map(v => v * 2)
.catch((err) => {
console.log("Caught Error, continuing")
//Return an empty Observable which gets collapsed in the output
return Rx.Observable.empty();
})
);
observable.subscribe(
(value) => console.log("onNext " + value), (error) => console.log("Error: " + error.message), () => console.log("Completed!")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>
Vous devez passer à un nouveau flux jetable. Si une erreur se produit, il sera éliminé en toute sécurité et conservez le flux d'origine:
Rx.Observable.from([0,1,2,3,4,5])
.switchMap(value => {
// This is the disposable stream!
// Errors can safely occur in here without killing the original stream
return Rx.Observable.of(value)
.map(value => {
if (value === 3) {
throw new Error('Value cannot be 3');
}
return value;
})
.catch(error => {
// You can do some fancy stuff here with errors if you like
// Below we are just returning the error object to the outer stream
return Rx.Observable.of(error);
});
})
.map(value => {
if (value instanceof Error) {
// Maybe do some error handling here
return `Error: ${value.message}`;
}
return value;
})
.subscribe(
(x => console.log('Success', x)),
(x => console.log('Error', x)),
(() => console.log('Complete'))
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>
Plus d'informations sur cette technique dans cet article de blog: La quête de boulettes géantes: continuez les flux RxJS en cas d'erreur
Vous pouvez réellement utiliser try/catch à l'intérieur de votre fonction map pour gérer l'erreur. Voici l'extrait de code
var source = Rx.Observable.from([0, 1, 2, 3, 4, 5])
.map(
function(value) {
try {
if (value === 3) {
throw new Error("Value cannot be 3");
}
return value;
} catch (error) {
console.log('I caught an error');
return undefined;
}
})
.filter(function(x) {
return x !== undefined; });
source.subscribe(
function(value) {
console.log("onNext " + value);
},
function(error) {
console.log("Error: " + error.message);
},
function() {
console.log("Completed!");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>