【问题标题】:managing state with FRP用 FRP 管理状态
【发布时间】:2013-08-15 13:44:35
【问题描述】:

有人说 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),并安排累积现在和未来抽奖事件之间的更改。当draw事件发生时,我需要绘制累积的变化。

这大约是六行代码,使用带有观察者模式的命令式样式,但我找不到在 FRP 中表达这一点的合理方式。唯一接近的事情是关闭共享状态上的相关事件流,并通过副作用显式管理状态和呈现事件。这几乎不是命令式回调的改进。

这在 FRP 中应该如何处理?

这是一个用于关闭状态的flajax实用程序:

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 中是否有更好的方法来做到这一点?不同的模式,还是不同的库?

【问题讨论】:

  • 我不熟悉flajax,但你也可以试试RxJs。它可能有不同的、更好的语法。另外,如果您想查看一些更复杂的 FRP 示例,请查看 ELM 语言 elm-lang.org

标签: javascript reactive-programming frp


【解决方案1】:

FRP 完全是关于管理状态的。但它是关于没有时间管理状态的。为此,您必须将状态保留在树或图中。这可以防止任何旧代码在某个随机时间点对其进行变异。

在 FRP 状态下,仅当父节点触发更新时才会更新。发生这种情况时,事件值(以及任何其他父值)用于计算新节点值。

blandw 上面的回答是正确的,因为 collectE 是你想要的。

在 collectE 中,该节点的前一个值是在其父节点触发时提供的。这允许您存储您希望的任何状态,例如更改的集合。但是这个集合只有在父事件触发时才会更新。

因此,通过将您的状态突变限制在父母更新时,您可以节省很多麻烦。用一个基本的例子很难看出这一点。当您从事大型项目时,这一点会变得更加明显。

但是要更新 blandw 的答案,除了从非 frp 系统中获取事件之外,不要出于任何原因使用 receiverE。这绝不应该发生在 FRP 图的中间,而只能作为没有父节点的顶级节点。 在任何其他情况下使用它都违反了 FRP 的全部要点。

【讨论】:

    【解决方案2】:

    这里有更多的flajax糖:而不是使用sampledBy使用snapshotE,它将在每个帧事件上对已经收集的更改数组进行快照。检查您的 google 群组主题,我已经为它编写了一些代码。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2015-08-15
        • 2014-07-21
        • 1970-01-01
        • 2020-11-26
        • 2020-07-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-18
        相关资源
        最近更新 更多