有人说FRP是关于在没有明确管理状态的情况下处理事件流。这个人,例如:
http://www.slideshare.net/borgesleonardo/functional-reactive-programming-in-clojurescript
其他人通过指出完全由副作用编程的困难来激励FRP,因为必须使用异步回调。
http://cs.brown.edu/~sk/Publications/Papers/Published/mgbcgbk-flapjax/
然而,在试验FRP(flapjax)时,我仍然遇到同样的问题:除了明确地通过副作用,无法处理状态。
例如,动画队列。更改到达事件流。当第一个更改到来时,我需要将绘制排队以便在将来某个时间发生(例如使用window.requestAnimationFrame),并安排在现在和将来的绘制事件之间累积更改。当绘制事件发生时,我需要绘制累积的变化。
这是使用具有观察者模式的命令式样式的大约六行代码,但我找不到在FRP中表达这种情况的合理方法。唯一接近的是涉及在共享状态下关闭相关事件流,并通过副作用显式管理状态和呈现事件。这在命令性回调中几乎没有改进。
这应该如何在FRP中处理?
这是一个用于关闭状态的flapjax实用程序:
function worldE(init, handlers) {
var r = fj.receiverE();
fj.forEach(function(h) {
h[0].mapE(function (ev) {
r.sendEvent(init = h[1](init, ev));
});
}, handlers);
return r;
}
这里它用于动画循环:
function initialize(opts) {
var blitE = fj.receiverE();
function accumulate(state, data) {
if (!state.queued) {
window.requestAnimationFrame(blitE.sendEvent);
}
return {queued: true, changes: _.extend({}, state.changes, data)};
}
function dodraw(state, _) {
draw(state.changes);
return {queued: false, changes: {}};
}
worldE({queued: false, changes: {}},
[[opts.data_source, accumulate], [blitE, dodraw]]);
}
注意事项:与同等的回调代码相比,它更大,可读性更低,维护更少。它仍然需要明确管理状态。它通过副作用运作。
在FRP中有更好的方法吗?不同的模式,或不同的库?
答案 0 :(得分:1)
我不熟悉Flapjax,但是查看文档,您可以使用collectE
创建一个累积状态的流。
然后,使用receiverE
和sendEvent
创建第二个animationFrame事件流。
最后,模仿bacon.js的sampledBy
(https://github.com/baconjs/bacon.js/wiki/Diagrams#sampledby)来创建[animationFrame,state]元组的第三个流。
答案 1 :(得分:0)
这里多了一些flapjax糖:而不是使用sampledBy使用snapshotE,快照已收集的快照会在每个帧事件上更改数组。检查你的谷歌群组主题,我已经为它编写了一些代码。