Slava Fomin II
Slava Fomin II

Reputation: 28611

Wait for all observables in mergeMap to complete before emitting a custom value

I want to process a list of observables concurrently using flatMap and then to emit a single empty value when all inner observables are processed. Is there an elegant way to achieve this, i.e. using a single operator?

Here's the example:

const { of, from } = Rx.Observable;

from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  .mergeMap(number => multiply(number), 2) // processing two numbers at a time
  .last() // waiting for all inner observables to complete
  .map(_ => undefined) // casting a value returned by last() to an empty value
  .subscribe()
;

function multiply(number) {
  return of(number * 2) // multiplying the number
    .delay(200) // adding a slight delay
  ;
}

I know I can use toArray() or last() to wait for all inner observables to complete, but then I will need to cast it to an empty value using map() operator (as in my example above).

I guess, I'm looking for an operator with the following semantics: emit X when source observable completes, e.g.:

from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  .mergeMap(number => multiply(number), 2)
  .emitOnComplete(undefined)
  .subscribe(console.log) // we should get undefined here
;

Upvotes: 1

Views: 3479

Answers (2)

martin
martin

Reputation: 96891

There's actually one sneaky solution using reduce() that emits only once when its source observable completes. You can use it to ignore all values and just return the seed value:

from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  .pipe(
    mergeMap(number => multiply(number), 2),
    reduce((acc, value) => acc, undefined),
  )
  .subscribe(console.log);

Live demo: https://stackblitz.com/edit/rxjs-tx6bbe

Btw, funny fact: The same trick with reduce() is used inside Angular's Router package (just without the seed value).

Upvotes: 2

Slava Fomin II
Slava Fomin II

Reputation: 28611

The most convenient way that I've managed to find so far is combining ignoreElements operator with endWith:

from([1, 2, 3, 4, 5])
  .mergeMap(number => multiply(number), 2)
  .ignoreElements()
  .endWith(undefined)
  .subscribe(console.log) // getting undefined here
;

However, it would be really nice to have a single operator for this.

Upvotes: 1

Related Questions