行为说明
嗯,实际上这并不容易解释。这是由于如何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
未指定,因此不能依赖 - 可能取决于浏览器(参见ES6 是否为对象属性引入了明确定义的枚举顺序?))。现在chrome
和firefox
最新版本似乎按字母数字属性的定义顺序枚举属性,但数字属性的数字顺序(遵循 ES2015 规范)。
所以在这里,driverA
首先连接到源,它启动相应的数据流。当driverB
连接到源时,同样的事情。由于您编写的方式,该数据流是同步B$
的。所以当subscribe
ie连线的时候,所有的数据都是a b c d
同步的,连线B$
的时候就已经完成了。鉴于接线是用 a 制成的,该接线会为您提供完成前最后发出的值,即.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
当数据流动时,所有源都已准备好接收它。