用FRP管理国家

时间:2013-08-13 19:32:11

标签: javascript reactive-programming frp

有人说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中有更好的方法吗?不同的模式,或不同的库?

2 个答案:

答案 0 :(得分:1)

我不熟悉Flapjax,但是查看文档,您可以使用collectE创建一个累积状态的流。 然后,使用receiverEsendEvent创建第二个animationFrame事件流。

最后,模仿bacon.js的sampledByhttps://github.com/baconjs/bacon.js/wiki/Diagrams#sampledby)来创建[animationFrame,state]元组的第三个流。

答案 1 :(得分:0)

这里多了一些flapjax糖:而不是使用sampledBy使用snapshotE,快照已收集的快照会在每个帧事件上更改数组。检查你的谷歌群组主题,我已经为它编写了一些代码。