即使其中一个来源未发出值,RxJS CombineLatest仍然有效

时间:2019-05-08 08:46:44

标签: angular rxjs rxjs6

我需要将两个来源的数据合并为一个res: {data1: any, data2: any}对象,并且即使其中一个来源没有发出任何值,我也需要实现这一目标

这是我期望的结构:

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

有没有可以执行此操作的rxjs运算符?

目前,我可以使用startWithcombineLatest的组合来解决此问题-我发出了空值,因此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)
    }
})

3 个答案:

答案 0 :(得分:1)

您可以使用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)
    }
});

答案 1 :(得分:1)

我知道这是一个旧线程。然而,我最近遇到了同样的问题并像@godblessstrawberry 一样解决了

  const source1 = new Subject(),
              source2 = new Subject();
        
        const vm$ = combineLatest([
            source1.pipe(startWith([{id: 1}])),
            source2.pipe(startWith(['abc'])),
        ])
            .pipe(map(([profile, page]) => ({profile, page})));
        
        vm$.subscribe(stream => {
            console.log({stream});
        })

答案 2 :(得分:0)

如@ritaj所述,您似乎已经做好了,尽管

  1. 只有在任何可观察项为空时,我才用defaultIfEmpty operator代替startWith。这是一个大理石图,用于比较两种方法:

startWith vs defaultIfEmpty with combineLatest operator

* 请注意,带有startWith的流发出两次

  1. 使用唯一对象(或符号)代替简单的null,以防万一源流确实发出null。这将确保我们仅过滤掉标记,而不是真实结果

  2. 在订阅中使用过滤器代替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))

^ Run this code with a marble diagram

希望这会有所帮助