我有以下代码:
FromEpohTimeMilliseconds([UNIXDATE])
我希望控制台上有三行:A,B和C,但我只得到最后一行。看来,即使B $ .tap(console.log)输出全部三个(“a”,“b”,“c”),driverC也只获取最后一条消息;
此行为的解释是什么?如何将所有三条消息传播到driverC?
版本:
答案 0 :(得分:1)
cycle.run
如何连接它的循环。以下代码在trycicle中运行:
const Cycle = require('@cycle/core');
const {Observable} = require('rx');
function main(sources) {
const B$ = sources.driverA
.concat(Observable.just('b'))
.concat(Observable.just('c'))
.concat(Observable.just('d'));
const C$ = sources.driverB.map(x => x.toUpperCase());
return {
driverA: Observable.just('a'),
driverB: B$,
driverC: C$
}
}
Cycle.run(main, {
driverA: (A$) => A$.tap(msg => console.log(msg)),
driverB: (B$) => B$.tap(msg => console.log(msg)),
driverC: msg$ => { msg$.subscribe(msg => console.log(msg)) }
});
并且只显示a d D
。所以它实际上是显示的最后一个字母。
现在如果你运行这个:
const Cycle = require('@cycle/core');
const {Observable} = require('rx');
function main(sources) {
const B$ = sources.driverA
.concat(Observable.just('b').delay(1))
.concat(Observable.just('c'))
.concat(Observable.just('d'));
const C$ = sources.driverB.map(x => x.toUpperCase());
return {
driverA: Observable.just('a'),
driverB: B$,
driverC: C$
}
}
Cycle.run(main, {
driverA: (A$) => A$.tap(msg => console.log(msg)),
driverB: (B$) => B$.tap(msg => console.log(msg)),
driverC: msg$ => { msg$.subscribe(msg => console.log(msg)) }
});
你得到a a A b B c C d D
这就是你所期望的。
发生的事情是run
通过主题将驱动程序连接到源,并按顺序执行。哪个订单? var x in obj
中属性的枚举顺序(未指定且因此无法依赖)可能与浏览器有关(参见Does ES6 introduce a well-defined order of enumeration for object properties?))。现在chrome
和firefox
最新版本似乎按照字母数字属性的定义顺序枚举属性,但是数值属性的数字顺序(following ES2015 spec)。
所以在这里,driverA
首先连接到源,它启动相应的数据流。当driverB
连接到源时,同样的事情。由于您编写B$
的方式,该数据流是同步。因此,当subscribe
即接线时,所有数据a b c d
从B$
同步流动,当driverC
接线时,B$
已经完成。鉴于接线是使用replaySubject(1)
进行的,该接线会在完成之前为您提供最后一个发射值d
。
因此,由于同步性,顺序很重要:如果B和C首先接线,那就没问题了。运气好的话,执行顺序不够。
为了说服您,我按照拓扑顺序对您的流进行排序的代码按预期工作:
const Cycle = require('@cycle/core');
const {Observable} = require('rx');
function main(sources) {
const B$ = sources.driverA
.concat(Observable.just('b'))
.concat(Observable.just('c'))
.concat(Observable.just('d'));
const C$ = sources.driverB.map(x => x.toUpperCase());
return {
driverC: C$,
driverB: B$,
driverA: Observable.just('a'),
}
}
Cycle.run(main, {
driverA: (A$) => A$.tap(msg => console.log(msg)),
driverB: (B$) => B$.tap(msg => console.log(msg)),
driverC: msg$ => { msg$.subscribe(msg => console.log(msg)) }})
要么按照拓扑顺序订购接收器,要么删除同步性。我添加了一个delay(1)
,以便在下一个时钟点继续数据流,此时driverC
已经连线以接收下一个值。这可能是最强大的选项,因为拓扑顺序在这里计算可能并不总是显而易见的,可能会随着源的隔行扫描而改变,并依赖于依赖于浏览器的对象属性枚举(!)。
另外,当无法避免数据流的同步时,通常先使用publish
连接所有源,然后connect
来处理连接问题,以便在数据流,所有来源都已准备好接收它。
答案 1 :(得分:1)
只需在delay
之后添加driverA
:
const B$ = sources.driverA.delay(1)
或者,您可以使用列出的所有可观察对象唤起concat
一次,并将其延迟。
const B$ = Observable.concat(
sources.driverA,
Observable.just('b'),
Observable.just('c'),
Observable.just('d')
).delay(1);
需要记住的是,main
函数只是连接管道。 run
打开了水。