Observable enfin sur abonnement

105

Selon cet artcle , onCompleteet la onErrorfonction du subscribesont mutuellement exclusives.

Ce qui signifie que l'un onErrorou l' autre des onCompleteévénements se déclenchera dans mon subscribe.
J'ai un bloc logique qui doit être exécuté que je reçoive une erreur ou que je termine mon flux d'informations avec succès.

J'ai recherché quelque chose comme finallyen python , mais tout ce que j'ai trouvé est celui finallyqui doit être attaché à l'observable que je crée.

Mais je veux faire cette logique uniquement lorsque je m'abonne et après la fin du flux, que ce soit avec succès ou avec une erreur.

Des idées?

Amir Tugi
la source

Réponses:

131

La variante "pipable" actuelle de cet opérateur est appelée finalize()(depuis RxJS 6). L'opérateur "patch" plus ancien et désormais obsolète a été appelé finally()(jusqu'à RxJS 5.5).

Je pense que l' finalize()opérateur est en fait correct. Vous dites:

ne faire cette logique que lorsque je m'abonne et après la fin du flux

ce qui n'est pas un problème je pense. Vous pouvez en avoir un sourceet l'utiliser finalize()avant de vous y abonner si vous le souhaitez. De cette façon, vous n'êtes pas obligé de toujours utiliser finalize():

let source = new Observable(observer => {
  observer.next(1);
  observer.error('error message');
  observer.next(3);
  observer.complete();
}).pipe(
  publish(),
);

source.pipe(
  finalize(() => console.log('Finally callback')),
).subscribe(
  value => console.log('#1 Next:', value),
  error => console.log('#1 Error:', error),
  () => console.log('#1 Complete')
);

source.subscribe(
  value => console.log('#2 Next:', value),
  error => console.log('#2 Error:', error),
  () => console.log('#2 Complete')
);

source.connect();

Cela imprime sur la console:

#1 Next: 1
#2 Next: 1
#1 Error: error message
Finally callback
#2 Error: error message

Janvier 2019: mise à jour pour RxJS 6

Martin
la source
1
Il est intéressant de noter que c'est un peu le modèle opposé des promesses, en ce que la finally()méthode est ajoutée en premier et que l'abonnement force impérativement la réussite / l'échec.
BradGreens
7
Ouais, c'est dommage. On pourrait penser que le finallybloc viendrait en dernier dans votre code.
d512
J'ai aimé le système de promesse d'Angular JS ... Comme le dit d512, je m'attendais à être "enfin" le dernier ... Je n'aime pas du tout ça ...
Sampgun
10
Depuis RXJS 5.5, "finalement" n'est plus une méthode observable. Utilisez plutôt l'opérateur "finaliser": source.pipe (finalize (() => console.log ('Enfin rappel'))). Subscribe (...); github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
Stevethemacguy
le problème avec finalize est qu'il attend un appel "complete ()". et si vous voulez un enfin sur chaque émission (si l'émission observable est réussie, faites a , si elle est erronée, faites plutôt b .. dans les deux cas, faites c )?
roberto tomás
65

La seule chose qui a fonctionné pour moi est ceci

fetchData()
  .subscribe(
    (data) => {
       //Called when success
     },
    (error) => {
       //Called when error
    }
  ).add(() => {
       //Called when operation is complete (both success and error)
  });
Hari Das
la source
26

J'utilise maintenant RxJS 5.5.7 dans une application angulaire et l'utilisation de l' finalizeopérateur a un comportement étrange pour mon cas d'utilisation car il est déclenché avant les rappels de succès ou d'erreur.

Exemple simple:

// Simulate an AJAX callback...
of(null)
  .pipe(
    delay(2000),
    finalize(() => {
      // Do some work after complete...
      console.log('Finalize method executed before "Data available" (or error thrown)');
    })
  )
  .subscribe(
      response => {
        console.log('Data available.');
      },
      err => {
        console.error(err);
      }
  );

J'ai dû utiliser la addméthode de l'abonnement pour accomplir ce que je voulais. Fondamentalement, un finallyrappel après le succès ou les rappels d'erreur sont effectués. Comme un try..catch..finallybloc ou une Promise.finallyméthode.

Exemple simple:

// Simulate an AJAX callback...
of(null)
  .pipe(
    delay(2000)
  )
  .subscribe(
      response => {
        console.log('Data available.');
      },
      err => {
        console.error(err);
      }
  );
  .add(() => {
    // Do some work after complete...
    console.log('At this point the success or error callbacks has been completed.');
  });
pcasme
la source
Heureux de vous aider.
pcasme