Подождите, пока все наблюдаемые в mergeMap завершатся, прежде чем испускать настраиваемое значение

Я хочу обрабатывать список наблюдаемых одновременно, используя flatMapа затем выдать одно пустое значение при обработке всех внутренних наблюдаемых. Есть ли элегантный способ добиться этого, то есть с помощью одного оператора?

Вот пример:

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

Я знаю, что могу использовать toArray() или last() чтобы дождаться завершения всех внутренних наблюдаемых, но тогда мне нужно будет привести его к пустому значению, используя map() оператор (как в моем примере выше).

Думаю, я ищу оператор со следующей семантикой: emit X when source observable completes, например:

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
;

2 ответа

На самом деле есть одно хитрое решение, использующее reduce()который излучается только один раз, когда его наблюдаемый источник завершается. Вы можете использовать его, чтобы игнорировать все значения и просто вернуть начальное значение:

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

Живая демонстрация: https://stackblitz.com/edit/rxjs-tx6bbe

Кстати, забавный факт: тот же трюк с reduce()используется внутри пакета Angular Router (только без начального значения).

Самый удобный способ, которым мне удалось найти до сих пор является объединение ignoreElements оператора с ENDWITH:

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

Однако было бы неплохо иметь для этого одного оператора.

Другие вопросы по тегам