打破Bacon.js中FRP蛇的循环

时间:2014-04-17 23:06:31

标签: javascript frp bacon.js

我一直关注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。

我能想到的最接近的是将appleslength合并为一个流,并使该流从"currentSnake"生成自己的currentPosition

applesAndLength --> currentPosition
         ^          ^
         |         /
        currentSnake

尽管如此,我还没有考虑过实施。

1 个答案:

答案 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切割周期,因为初始值往往会丢失;因此重新排序appleslength