Rxjs 从等待到所有来源产生一个值

Rxjs 从等待到所有来源产生一个值,rxjs,Rxjs,我以正常方式使用RxJS中的with latest from操作符: var combined = source1.withLatestFrom(source2, source3); …从source2和source3主动收集最近的排放量,并仅在source1排放时排放所有三个值 但我不能保证source2或source3在source1生成值之前会生成值。相反,我需要等到所有三个源都产生至少一个值,然后才能让withLatestFrom执行它的操作 合同需要是:如果source1发出,那么组

我以正常方式使用RxJS中的
with latest from
操作符:

var combined = source1.withLatestFrom(source2, source3);
…从
source2
source3
主动收集最近的排放量,并仅在
source1
排放时排放所有三个值

但我不能保证
source2
source3
source1
生成值之前会生成值。相反,我需要等到所有三个源都产生至少一个值,然后才能让
withLatestFrom
执行它的操作

合同需要是:如果
source1
发出,那么
组合的
始终最终在其他源最终产生时发出。如果
source1
在等待其他源时多次发射,我们可以使用最新值并放弃以前的值编辑:作为大理石图:

--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--
我可以为此创建一个自定义操作符,但我想确保我没有错过一个使用普通操作符的明显方法。感觉就像我想在初始发射时使用
combinelatetest
,然后从那时起切换到
withLatestFrom
,但我一直不知道如何做到这一点

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

var Dispatcher = new Rx.Subject();
var source1 = Dispatcher.filter(x => x === 'foo');
var source2 = Dispatcher.filter(x => x === 'bar');
var source3 = Dispatcher.filter(x => x === 'baz');

var combined = source1.publish(function(s1) {
    return source2.publish(function(s2) {
        return source3.publish(function(s3) {
            var cL = s1.combineLatest(s2, s3).take(1).do(() => console.log('cL'));
            var wLF = s1.skip(1).withLatestFrom(s2, s3).do(() => console.log('wLF'));

            return Rx.Observable.merge(cL, wLF);
        });
    });
});

var sub1 = combined.subscribe(x => console.log('x', x));

// These can arrive in any order
// and we can get multiple values from any one.
Dispatcher.onNext('foo');
Dispatcher.onNext('bar');
Dispatcher.onNext('foo');
Dispatcher.onNext('baz');

// combineLatest triggers once we have all values.
// cL
// x ["foo", "bar", "baz"]

// withLatestFrom takes over from there.
Dispatcher.onNext('foo');
Dispatcher.onNext('bar');
Dispatcher.onNext('foo');
// wLF
// x ["foo", "bar", "baz"]
// wLF
// x ["foo", "bar", "baz"]

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


我认为答案大致与您描述的一样,让第一个值为
combinelatetest
,然后切换到
withLatestFrom
。我的JS是模糊的,但我认为它看起来像这样:

var selector = function(x,y,z) {};

var combined = Rx.Observable.concat(
    source1.combineLatest(source2, source3, selector).take(1),
    source1.withLatestFrom(source2, source3, selector)
);
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)
            );
        });
    });
});
您可能应该使用
publish
来避免多个订阅,因此如下所示:

var selector = function(x,y,z) {};

var combined = Rx.Observable.concat(
    source1.combineLatest(source2, source3, selector).take(1),
    source1.withLatestFrom(source2, source3, selector)
);
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
有问题,而
with latest from
没有得到值。我认为以下方法可行:

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)
    )
)));

…因此,使用
combinelatetest
获取一个值,然后使用
with latestfrom
获取其余值,实际上
with latestfrom
已经

  • 等待每个来源
  • 仅当source1发射时发射
  • 仅记住最后一条source1消息,而其他源尚未启动
//当源1发出时,其他源已经发出
var source1=Rx.可观测间隔(500).取值(7)
var source2=Rx.可观测间隔(100300).取(10)
var source3=Rx.可观测间隔(200).取值(10)
变量选择器=(a,b,c)=>[a,b,c]
资料来源1
.withLatestFrom(源2、源3、选择器)
.subscribe()
vs


我有类似的要求,但只有2个观察。 我首先使用了switchMap+:

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

  • 等待,直到两个观察值都发出一些值
  • 仅当第一个观察值已更改时才从第二个观察值中提取值(与CombineTest不同)
  • 不挂起第二个可观察对象(因为.first())
在我的例子中,第二个可观察对象是一个ReplaySubject。我不确定它是否适用于其他可观察类型

我认为:

  • flatMap可能也会起作用
  • 可以扩展这种方法来处理2个以上的观测值

我很惊讶
with latest from
不会等待第二次观察。

我对接受的答案不太满意,所以我最终找到了另一个解决方案。给猫剥皮有很多方法

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


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

const first=token$.first()
可观察合并(
请求$.buffer(第一个).mergeAll(),
请求$.skipUntil(第一个)
)
.withLatestFrom(令牌$)

现场查看:

用例是什么?你在找
zip
zip
不行,因为这三种来源的产量相差悬殊。用例是
source1
通常是一种人机交互,比如点击,其他源从不同的源获取数据——ajax响应、SSE流等等<代码>加入
似乎非常接近:您是否尝试过仅使用withLatestFrom?根据文档和我观察到的行为,withLatestFrom方法实际上是在等待每个源生成。仅使用withLatestFrom即可满足您的全部要求。从另一个角度来看:发布嵌套是处理运算符切换问题的一种有趣的方式。根据我对LatestFrom的经验,它确实会等待每个源生成,但这意味着它会跳过在该状态发生之前发生的任何事件。我遇到了一个与OP类似的问题,S1发出其大部分或全部值,S2发出一个值;我想让它等待S2,然后用该值为每个S1值发射,但它只是跳过最后一个S1值。谢谢,我认为你在这方面做得对。在它周围玩看起来像是
concat
懒洋洋地订阅第二个可观察对象,因此
with latest from
直到
combinelatetest
完成后才累积值。使用
merge
而不是急切地订阅