RxJS объединитьПоследний, даже если один из источников не выдает значения - PullRequest
0 голосов
/ 08 мая 2019

Мне нужны данные из двух источников для объединения в один res: {data1: any, data2: any} объект, и мне нужно добиться этого , даже если один из источников не излучает никаких значений

Вотструктура, которую я ожидаю:

xxx (
    source1,
    source2,
    (data1, data2) => ({data1: data1, data2: data2})
).subscribe(res => {
    doSomething1(res.data1)
    doSomething2(res.data2)
})

Есть ли какие-либо операторы rxjs, которые могут это сделать?

В настоящее время я могу решить эту проблему с помощью комбинации startWith и combineLatest - я выдаю нулевое значение, такcombineLatest может начать излучать значения - любой лучший способ решить эту проблему без startWith(null)?

combineLatest (
    source1.pipe(startWith(null)),
    source2.pipe(startWith(null)),
    (data1, data2) => ({data1: data1, data2: data2})
).subscribe(res => {
    if(res.data1) {
        doSomething1(res.data1)
    }
    if(res.data2) {
        doSomething2(res.data2)
    }
})

Ответы [ 2 ]

1 голос
/ 08 мая 2019

Вы можете использовать BehaviorSubject .Это предоставляет вам поток, который выдает значение по умолчанию при подписке, если более свежее значение недоступно (в данном случае null).

const subject1 = new BehaviorSubject(null),
      subject2 = new BehaviorSubject(null);

source1.subscribe(subject1);
source2.subscribe(subject2);

combineLatest(subject1, subject2).subscribe(res => {
    if(res.data1) {
        doSomething1(res.data1)
    }
    if(res.data2) {
        doSomething2(res.data2)
    }
});
0 голосов
/ 09 мая 2019

Как уже упоминалось @ritaj, вы, кажется, уже все делаете нормально, хотя :

  1. Я бы заменил startWith на оператор defaultIfEmpty , чтобы продолжить, только если какая-либо из наблюдаемых пуста.Вот мраморная диаграмма для сравнения двух подходов:

startWith vs defaultIfEmpty with combineLatest operator

* Обратите внимание, что поток с startWith излучает дважды

Используйте уникальный объект (или символ) вместо простого null, на случай, если исходный поток действительно испускает null.Это гарантирует, что мы будем отфильтровывать только наши маркеры, но не реальные результаты

Используйте фильтр вместо if-else в подписке - должно выглядеть немного чище.Это общая хорошая практика - сохранять .subscribe как можно более тонким

Вот пример:

const NO_VALUE = {};

const result$ = combineLatest(
  a$.pipe(  defaultIfEmpty(NO_VALUE)  ),
  b$.pipe(  defaultIfEmpty(NO_VALUE)  )
)
.pipe(filter(([a, b]) => a !== NO_VALUE || b !== NO_VALUE))

^ Запустите этот кодс мраморной диаграммой .

Надеюсь, это поможет

...