希望有人可以帮我解决这个问题。 我有两个流,我需要使用运算符combineLatest。过了一会儿,我需要添加动态流,还需要使用combineLatest。 这是我需要做的:
stream a ---------a---------------b-------------c------------------------>
stream b ----1--------2-----3-------------------------4------------------>
stream c (not defined at start) -----z-----------------x------------>
stream d (not defined at start) ----------k------>
(combineLatest)
result ---------(a1)(a2)--(a3)--(b3)----(b3z)-(c3z)-(c4z)-(c4x)-(c4xk)->
更新
更具体一点我想转此STREAM (link)
结果如下:
A----B---B0-C0--D0--D1--E1--E1a--F1a--F2a---G2a---G3a--H3a-H3b--I3b
答案 0 :(得分:2)
everything is a stream的想法。甚至溪流:)
const onNew$ = new Rx.Subject();
const a$ = Rx.Observable.interval(1000).mapTo('a');
const b$ = Rx.Observable.interval(1000).mapTo('b');
const comb$ = Rx.Observable
.merge(
onNew$,
Rx.Observable.from([a$, b$]),
)
.scan((acc, v) => {
acc.push(v);
return acc;
}, [])
.switchMap(vs => Rx.Observable.combineLatest(vs))
comb$.take(4).subscribe(v => console.log(v));
setTimeout(
() => onNew$.next(Rx.Observable.interval(1000).mapTo('c')),
2000,
);
setTimeout(
() => onNew$.next(Rx.Observable.interval(1000).mapTo('d')),
4000,
);

<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>
&#13;
答案 1 :(得分:1)
采用Oles的答案,简化一点并添加问题更新中给出的测试数据
const Subject = Rx.ReplaySubject
const ReplaySubject = Rx.ReplaySubject
const newStream = new Subject()
// Set up output, no streams yet
const streamOfStreams = newStream
.scan( (acc, stream) => {
acc.push(stream);
return acc;
}, [])
.switchMap(vs => Observable.combineLatest(vs))
.map(arrayOfValues => arrayOfValues.join('')) // declutter
.subscribe(console.log)
// Add a stream
const s1 = new ReplaySubject()
newStream.next(s1)
// emit on streams
s1.next('A'); s1.next('B')
// Add a stream
const s2 = new ReplaySubject()
newStream.next(s2)
// emit on streams
s2.next('0'); s1.next('C')
s1.next('D'); s2.next('1'); s1.next('E');
// Add a stream
const s3 = new ReplaySubject()
newStream.next(s3)
// emit on streams
s3.next('a');
s1.next('F'); s2.next('2'); s1.next('G'); s2.next('3'); s1.next('H');
s3.next('b'); s1.next('I')
工作示例:CodePen
Christian慷慨地提供了一些测试流,这些测试流比我上面使用的测序主题更“真实”。不幸的是,这些突出显示了解决方案中的一个错误。
作为参考,新的测试流是
const streamA = Rx.Observable.timer(0,800).map(x => String.fromCharCode(x+ 65));
const streamB = Rx.Observable.timer(0,1300).map(x => x);
const streamC = Rx.Observable.timer(1100, 2000).map(x => String.fromCharCode(x+ 97));
setTimeout(() => newStream.next(streamA), 500);
setTimeout(() => newStream.next(streamB), 2000);
setTimeout(() => newStream.next(streamC), 3000);
问题#1
第一个问题源于streamOfStreams
,
.switchMap(vs => Observable.combineLatest(vs))
这基本上说,每当出现一个新的数组流时,将其映射到新数组的combineLatest()
并切换到新的observable。但是,测试可观察量很冷,这意味着每次重新订阅都会获得完整的流。
参考:Introduction to Rx - Hot and Cold observables
实际上,一些可观察到的序列看起来很热 冷。令人惊讶的几个例子是Observable.Interval 和Observable.Timer
所以我们得到了
- 预期A--B--B0...
- 实际A--B--A0--B0...
显而易见的解决方案是将寒冷的观察者变热,
const asHot = (stream) => {
const hot = stream.multicast(() => new Rx.Subject())
hot.connect()
return hot
}
但这省略了序列中的B0 A--B--C0...
,所以我们想要热的+ 1之前的,可以使用缓冲区大小为1
const asBuffered = (stream) => {
const bufferOne = new ReplaySubject(1)
stream.subscribe(value => bufferOne.next(value))
return bufferOne
}
问题#2
第二个问题来自于streamC延迟它首次发射1100ms的事实(好的测试基督徒!)。
结果是
- 预期A--B--B0--C0--D0--D1--E1--E1a...
- 实际A--B--B0--C0--D0--E1a...
这意味着我们需要延迟添加流,直到它首次发出
const addStreamOnFirstEmit = (stream) => {
const buffered = asBuffered(stream)
buffered.first().subscribe( _ => {
newStream.next(buffered)
})
}
工作示例:CodePen
我已经离开各种 streamAdder 函数进行实验,还有_debug
版本发出流和addStream事件来显示序列。
还限制了源流,以便控制台不会滚动太多。
新解决方案与'G3a'之后问题中给出的预期输出不同
A----B---B0-C0--D0--D1--E1--F1---F2---F2a---G2a---G3a--H3a--H3b--I3b
A----B---B0-C0--D0--D1--E1--E1a--F1a--F2a---G2a---G3a--G3b--H3b--I3b
这是由于同时发射'H'和'b'。问题#3?
为了查看解决方案是否失败,如果streamC延迟第一次发射直到两次发出streamA&amp; streamB,我把延迟改为1800ms
const streamC = Rx.Observable.timer(1800, 2000).map(x => String.fromCharCode(x+ 97));
我相信此测试的输出是正确的。
答案 2 :(得分:0)
如果您可以取消订阅并重新订阅每个新流
,则可以这样做// Start with two streams
const s1 = new ReplaySubject(1)
const s2 = new ReplaySubject(1)
let out = Observable.combineLatest(s1, s2)
let subscription = out.subscribe(console.log)
s2.next('1'); s1.next('a'); s2.next('2'); s2.next('3'); s1.next('b')
// Add a new stream
subscription.unsubscribe()
const s3 = new ReplaySubject(1)
out = Observable.combineLatest(s1, s2, s3)
subscription = out.subscribe(console.log)
s3.next('z'); s1.next('c'); s2.next('4'); s3.next('x')
// Add a new stream
subscription.unsubscribe()
const s4 = new ReplaySubject(1)
out = Observable.combineLatest(s1, s2, s3, s4)
subscription = out.subscribe(console.log)
s4.next('k')
工作示例:CodePen