Observable finalmente en la suscripción

105

De acuerdo con este artículo , onCompletey la onErrorfunción de los subscribeson mutuamente excluyentes.

Es decir, onErroro los onCompleteeventos se dispararán en mi subscribe.
Tengo un bloque lógico que debe ejecutarse si recibo un error o si termino mi flujo de información con éxito.

Busqué algo como finallyen Python , pero todo lo que encontré es finallyque debe adjuntarse al observable que creo.

Pero quiero hacer esa lógica solo cuando me suscriba, y después de que la transmisión haya terminado, ya sea con éxito o con un error.

¿Algunas ideas?

Amir Tugi
fuente

Respuestas:

130

La variante "pipable" actual de este operador se llama finalize()(desde RxJS 6). Se llamó al operador "parche" más antiguo y ahora obsoleto finally()(hasta RxJS 5.5).

Creo que el finalize()operador tiene razón. Tu dices:

haz esa lógica solo cuando me suscribo y después de que la transmisión haya terminado

lo cual no es un problema, creo. Puedes tener uno sourcey usarlo finalize()antes de suscribirte si quieres. De esta manera, no es necesario que use siemprefinalize() :

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();

Esto se imprime en la consola:

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

Enero de 2019: actualizado para RxJS 6

martín
fuente
1
Es interesante que sea una especie de patrón opuesto a Promesas, ya que el finally()método se agrega primero y la suscripción obliga imperativamente a aprobar / reprobar.
BradGreens
7
Sí, eso es una lástima. Uno pensaría que el finallybloque sería el último en su código.
d512
Me gustó el sistema de promesa de Angular JS ... Como dice d512, esperaba que "finalmente" fuera el último ... No me gusta esto en absoluto ...
Sampgun
10
A partir de RXJS 5.5, "finalmente" ya no es un método observable. Utilice el operador "finalize" en su lugar: source.pipe (finalize (() => console.log ('Finalmente devolución de llamada'))). Subscribe (...); github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
Stevethemacguy
el problema con finalize es que espera una llamada "complete ()". ¿Qué pasa si desea un finalmente en cada emisión (si la emisión observable es exitosa, haga a , si tiene errores, haga b en su lugar ... en ambos casos, haga c )?
roberto tomás
65

Lo único que funcionó para mí es esto

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

Ahora estoy usando RxJS 5.5.7 en una aplicación Angular y el uso del finalizeoperador tiene un comportamiento extraño para mi caso de uso, ya que se activa antes de las devoluciones de llamada de éxito o error.

Ejemplo 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);
      }
  );

He tenido que usar addmedhod en la suscripción para lograr lo que quiero. Básicamente, una finallydevolución de llamada después de que se realizan las devoluciones de llamada de éxito o error. Como un try..catch..finallybloque o Promise.finallymétodo.

Ejemplo 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
fuente
Encantado de ayudarle.
pcasme