我正在以正常方式使用RxJS中的withLatestFrom
运算符:
var combined = source1.withLatestFrom(source2, source3);
...主动收集来自source2
和source3
的最新发射,并仅在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
答案 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$)
答案 2 :(得分:0)
在找到第一个完整集之前,使用combineLatest
和filter
删除元组,然后设置变量以停止过滤。变量可以在包装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]) => {...}));
所以:
就我而言,第二个observable是ReplaySubject。我不确定它是否适用于其他可观察类型。
我认为:
我很惊讶withLatestFrom
不会等待第二次观察。
答案 4 :(得分:-3)
实际上withLatestFrom
已经
// 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()