【问题标题】:RxJS combineLatest even if one of the sources is not emitting valuesRxJS combineLatest 即使其中一个源没有发出值
【发布时间】:2019-05-08 08:46:44
【问题描述】:

我需要将来自两个来源的数据组合成一个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)
    }
})

【问题讨论】:

  • any better way to solve this without startWith(null)? 不。这就是 combineLatest 的工作原理。你真的需要 combineLatest 吗?
  • @ritaj 不,我需要的是至少从一个来源获取价值,如果其他来源已经死了
  • 使用startWith 是解决您问题的正常方法。

标签: angular rxjs rxjs6


【解决方案1】:

正如@ritaj 已经提到的,你似乎已经做得很好了,虽然

  1. 我会将startWith 替换为defaultIfEmpty 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.

希望对你有帮助

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      我知道这是一个旧线程。但是,我最近遇到了同样的问题并像@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});
              })
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-07-12
        • 2019-08-25
        • 1970-01-01
        • 1970-01-01
        • 2019-05-05
        • 1970-01-01
        • 2017-06-25
        • 1970-01-01
        相关资源
        最近更新 更多