我一直关注this snake example并决定修改它以仅在空(即非蛇)细胞中生成新的苹果。然而,这引入了Observables之间的循环依赖,因为现在生成新的苹果不仅取决于最后的位置而且取决于整条蛇:
// stream of last `length` positions -- snake cells
var currentSnake = currentPosition.slidingWindowBy(length);
// stream of apple positions
var apples = appleStream(currentSnake);
// length of snake
var length = apples.scan(1, function(l) { return l + 1; });
有没有一种很好的方法来解决这个循环?
我可以想象这将如何在凌乱的状态机中工作,而不是干净的FRP。
我能想到的最接近的是将apples
和length
合并为一个流,并使该流从"currentSnake"
生成自己的currentPosition
。
applesAndLength --> currentPosition
^ ^
| /
currentSnake
尽管如此,我还没有考虑过实施。
答案 0 :(得分:4)
一旦构建完成,培根通常可以处理Observable
之间的循环依赖。正在构建它们有点棘手。
在像Javascript这样的语言中,要创建一个带有循环的结构(即双向链表),您需要一个可变变量。对于常规对象,您可以使用常规变量或字段来执行此操作,例如
var tail = { prev: null, next: null };
var head = { prev: null, next: tail };
tail.prev = head; // mutating 'tail' here!
在Bacon中,我们使用Observables而不是变量和对象,因此我们需要某种可变的observable来达到相同的目的。值得庆幸的是,Bacon.Bus
只是我们需要的一种可观察性:
var apples = new Bacon.Bus(); // plugged in later
var length = apples.scan(1, function(l) { return l + 1; });
var currentSnake = currentPosition.slidingWindowBy(length);
apples.plug(appleStream(currentSnake)); // mutating 'apples' here!
根据我的经验,最好在EventStream
s而不是Properties
切割周期,因为初始值往往会丢失;因此重新排序apples
和length
。