web-dev-qa-db-fra.com

RxJS - observable ne se termine pas lorsqu'une erreur se produit

Lorsque je crée un observable à partir de zéro et que l'erreur d'observation est terminée, la partie terminée de l'abonnement n'est jamais invoquée.

var observer = Rx.Observable.create(function(observer){
    observer.onError(new Error('no!'));
    observer.onCompleted();
})

observer.subscribe(
    function(x) { console.log('succeeded with ' + x ) },
    function(x) { console.log('errored with ' + x ) },
    function() { console.log('completed') }
)

La sortie est:

errored with Error: no!

Je m'attends à ce que ce soit:

errored with Error: no!
completed

Si je change le code pour invoquer onNext au lieu de onError, l'observable se termine correctement:

var observer = Rx.Observable.create(function(observer){
    observer.onNext('Hi!');
    observer.onCompleted();
})

observer.subscribe(
    function(x) { console.log('succeeded with ' + x ) },
    function(x) { console.log('errored with ' + x ) },
    function() { console.log('completed') }
)

J'obtiens la sortie attendue:

succeeded with Hi! 
completed

Pourquoi ne se termine-t-il pas lorsqu'une erreur s'est produite?

39
Oved D

C'est parce qu'une erreur signifie la fin, donc le rappel associé à onCompleted n'est jamais appelé. Vous pouvez consulter ici le contrat Rxjs pour les observables ( http://reactivex.io/documentation/contract.html ):

Un observable peut faire zéro ou plusieurs notifications OnNext, chacune représentant un seul élément émis, et il peut ensuite suivre ces notifications d'émission par une notification OnCompleted ou OnError, mais pas les deux. Lors de l'émission d'une notification OnCompleted ou OnError, il ne peut plus émettre de notifications ultérieures. "

Pour la gestion des erreurs, vous pouvez consulter: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/errors.md

44
user3743222

Pendant que je posais la même question, je suis tombé sur ce problème github .

Apparemment, la méthode finally de l'objet Observable doit être utilisée dans ce cas.

Citant Aleksandr-Leotech à partir de ce fil:

Complet et finalement sont des choses totalement différentes. Terminé signifie que la vapeur observable s'est terminée avec succès. Parce que vous pouvez avoir de nombreux appels à succès. Enfin, cela signifie que Steam s'est terminé, avec succès ou non.

Ce n'est pas évident avec les requêtes HTTP, mais imaginez deux scénarios supplémentaires.

  1. Événements de souris. Vous recevrez un rappel sans fin de Steam de succès, mais vous ne recevrez jamais définitivement ou complètement, car les événements utilisateur ne s'arrêteront jamais (sauf si vous déclenchez une exception avec un code de bogue, vous obtiendrez une erreur et enfin).

  2. Travailler avec des sockets Web. Vous obtiendrez plusieurs rappels de réussite, mais à un moment donné, votre communication avec le serveur principal s'arrêtera et vous obtiendrez à la fois complète et enfin, sauf si vous avez des erreurs, ce qui appellera l'erreur et enfin.

Ainsi, vous pourriez recevoir plusieurs ou aucun appel de succès, zéro ou un appel d'erreur, zéro ou un complet et zéro ou un finalement.

14
coni2k

Une autre solution, probablement la plus simple, pourrait être d'utiliser la fonction add().
Dans ce cas, l'instruction sera toujours exécutée quelle que soit l'erreur survenue ou l'appel réussi (de même finally dans la plupart des langages de programmation).

observer.subscribe(
    function(x) { console.log('succeeded with ' + x ) },
    function(x) { console.log('errored with ' + x ) },
    function() { console.log('completed') }
)
.add(() => {
    console.log("Will be executed on both success or error of the previous subscription")
);
3
Just Shadow