Дождитесь завершения всех наблюдаемых в mergeMap, прежде чем выдавать пользовательское значение - PullRequest
1 голос
/ 24 марта 2020

Я хочу обрабатывать список наблюдаемых одновременно, используя 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 ]

1 голос
/ 24 марта 2020

На самом деле есть одно хитрое решение, использующее 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 (только без начального значения).

0 голосов
/ 24 марта 2020

Самый удобный способ, который мне удалось найти, - это объединить оператор ignoreElements с endWith :

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

Однако это будет действительно приятно иметь один оператор для этого.

...