withLatestFrom等待所有来源产生一个值

时间:2016-08-23 09:43:16

标签: rxjs

我正在以正常方式使用RxJS中的withLatestFrom运算符:

var combined = source1.withLatestFrom(source2, source3);

...主动收集来自source2source3的最新发射,并仅在source1发出时发出所有三个值。

但我不能保证{/ 1}}或source2会在 source3产生值之前产生值。相反,我需要等到所有三个来源各自产生至少一个值,然后让source1做它的事情。

合同必须是:如果withLatestFrom发出source1,那么始终最终会在其他来源最终产生时发出。如果combined在等待其他来源时多次发出,我们可以使用最新值并丢弃之前的值。 编辑:作为大理石图表:

source1

我可以为此创建一个自定义运算符,但我想确保我没有错过使用vanilla运算符执行此操作的明显方法。感觉就像我希望--1------------2---- (source) ----a-----b--------- (other1) ------x-----y------- (other2) ------1ax------2by-- --1------------2---- (source) ------a---b--------- (other1) --x---------y------- (other2) ------1ax------2by-- ------1--------2---- (source) ----a-----b--------- (other1) --x---------y------- (other2) ------1ax------2by-- 用于初始发射,然后从切换combineLatest从此开始,但我还是无法弄清楚如何做到这一点。

编辑:最终解决方案的完整代码示例:

withLatestFrom

5 个答案:

答案 0 :(得分:4)

我认为答案或多或少与你所描述的一样,让第一个值为Option Strict On Module Module1 Sub Main() Dim x As Decimal = CDec(1.26) Dim y As Decimal = CDec(1.25) Dim z As Long = CLng(x + y) Dim F As Long = CLng(x) Dim G As Long = CLng(y) Dim J As Long = F + G Console.WriteLine(z) Console.WriteLine(J) Console.ReadLine() End Sub End Module ,然后切换到combinedLatest。我的JS很模糊,但我觉得它看起来像这样:

withLatestFrom

您应该使用var selector = function(x,y,z) {}; var combined = Rx.Observable.concat( source1.combineLatest(source2, source3, selector).take(1), source1.withLatestFrom(source2, source3, selector) ); 来避免多次订阅,因此看起来像这样:

publish

或使用箭头功能...

var combined = source1.publish(function(s1)
{
    return source2.publish(function(s2)
    {
        return source3.publish(function(s3)
        {
            return Rx.Observable.concat(
                s1.combineLatest(s2, s3, selector).take(1),
                s1.withLatestFrom(s2, s3, selector)
            );
        });
    });
});

修改

我发现var combined = source1.publish(s1 => source2.publish(s2 => source3.publish(s3 => Rx.Observable.concat( s1.combineLatest(s2, s3, selector).take(1), s1.withLatestFrom(s2, s3, selector) ) ))); 存在问题,concat未获取值。我认为以下内容可行:

withLatestFrom

...因此,使用var combined = source1.publish(s1 => source2.publish(s2 => source3.publish(s3 => Rx.Observable.merge( s1.combineLatest(s2, s3, selector).take(1), s1.skip(1).withLatestFrom(s2, s3, selector) ) ))); 获取一个值,然后使用combineLatest获取其余值。

答案 1 :(得分:3)

我对接受的答案不太满意,所以我最终找到了另一种解决方案。许多方法给猫皮肤!

我的用例只涉及两个流 - “请求”流和“令牌”流。我希望请求在收到后立即触发,使用最新的令牌。如果还没有令牌,那么它应该等到第一个令牌出现,然后触发所有挂起的请求。

我对接受的答案不太满意,所以我最终找到了另一种解决方案。基本上我将请求流分成两部分 - 在第一个令牌到达之前和之后。我缓冲了第一部分,然后一旦我知道令牌流非空,就重新释放所有内容。

const first = token$.first()

Rx.Observable.merge(
  request$.buffer(first).mergeAll(),
  request$.skipUntil(first)
)
  .withLatestFrom(token$)

在此处观看:https://rxviz.com/v/VOK2GEoX

答案 2 :(得分:0)

在找到第一个完整集之前,使用combineLatestfilter删除元组,然后设置变量以停止过滤。变量可以在包装defer的范围内,以正确执行操作(支持重新订阅)。这是在java中(但RxJ中存在相同的运算符):

Observable.defer(
    boolean emittedOne = false;
    return Observable.combineLatest(s1, s2, s3, selector)
        .filter(x -> {
            if (emittedOne) 
               return true;
            else {
               if (hasAll(x)) {
                   emittedOne = true;
                   return true;
               } else 
                   return false; 
            }
        });
)

答案 3 :(得分:0)

我有类似的要求,但只有2个可观测量。 我最后使用了switchMap +:

observable1
 .switchMap(() => observable2.first(), (a, b) => [a, b])
 .subscribe(([a, b]) => {...}));

所以:

  • 等待两个可观察者都发出一些值
  • 仅在第一个可观察的值(与combineLatest不同)
  • 时从第二个observable中提取值
  • 不挂起订阅第二个observable(因为.first())

就我而言,第二个observable是ReplaySubject。我不确定它是否适用于其他可观察类型。

我认为:

  • flatMap也可能会起作用
  • 可以扩展此方法以处理2个以上的observable

我很惊讶withLatestFrom不会等待第二次观察。

答案 4 :(得分:-3)

实际上withLatestFrom已经

  • 等待每个来源
  • 仅在source1发出
  • 时才会发出
  • 仅记住最后一封source1消息,而其他消息来源尚未启动
// when source 1 emits the others have emitted already
var source1 = Rx.Observable.interval(500).take(7)
var source2 = Rx.Observable.interval(100, 300).take(10)
var source3 = Rx.Observable.interval(200).take(10)

var selector = (a,b,c) => [a,b,c]
source1
  .withLatestFrom(source2, source3, selector)
  .subscribe()

VS

// source1 emits first, withLatestFrom discards 1 value from source1
var source1 = Rx.Observable.interval(500).take(7)
var source2 = Rx.Observable.interval(1000, 300).take(10)
var source3 = Rx.Observable.interval(2000).take(10)

var selector = (a,b,c) => [a,b,c]
source1
  .withLatestFrom(source2, source3, selector)
  .subscribe()