Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rxjs5 merge and error handling

Tags:

rxjs

rxjs5

I would like to combine/merge multiple Observables and when each of them is completed execute a finally function. The merge operator seems to execute each subscription in parallel, which is what I need, but if any of them throws an error the execution is halted.

RxJS version 4 has an operator mergeDelayError that should keep the all subscriptions executing till all of them are completed, but this operator isn't implemented in version 5.

Should I revert to a different operator?

var source1 = Rx.Observable.of(1,2,3).delay(3000);
var source2 = Rx.Observable.throw(new Error('woops'));
var source3 = Rx.Observable.of(4,5,6).delay(1000);

// Combine the 3 sources into 1 

var source = Rx.Observable
  .merge(source1, source2, source3)
  .finally(() => {

    // finally is executed before all 
    // subscriptions are completed.

    console.log('finally');

  }); 

var subscription = source.subscribe(
  x => console.log('next:', x),
  e => console.log('error:', e),
  () => console.log('completed'));

JSBin

like image 766
null Avatar asked Aug 17 '17 14:08

null


2 Answers

We can avoid blocking the stream by collecting the errors and emitting them at the end.

function mergeDelayError(...sources) {
  const errors = [];
  const catching = sources.map(obs => obs.catch(e => {
    errors.push(e);
    return Rx.Observable.empty();
  }));
  return Rx.Observable
    .merge(...catching)
    .concat(Rx.Observable.defer(
      () => errors.length === 0 ? Rx.Observable.empty() : Rx.Observable.throw(errors)));
}


const source1 = Rx.Observable.of(1,2,3);
const source2 = Rx.Observable.throw(new Error('woops'));
const source3 = Rx.Observable.of(4,5,6);

mergeDelayError(source1, source2, source3).subscribe(
  x => console.log('next:', x),
  e => console.log('error:', e),
  () => console.log('completed'));
like image 155
Laurence Rowe Avatar answered Jan 01 '23 02:01

Laurence Rowe


I think you can simulate the same behavior by using catch(). You'll just need to append it to every source Observable:

const sources = [source1, source2, source3].map(obs => 
  obs.catch(() => Observable.empty())
);

Rx.Observable
  .merge(sources)
  .finally(...)
  ...
like image 28
martin Avatar answered Jan 01 '23 02:01

martin