有人说 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 中处理?
这是一个用于关闭状态的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 中做到这一点?不同的模式,还是不同的库?