功能反应式编程(RX)中的合并性能

merge performance in Functional Reactive programming (RX)

在下面的代码中:

http://jsfiddle.net/staltz/4gGgs/27/

var clickStream = Rx.Observable.fromEvent(button, 'click');

var multiClickStream = clickStream
    .buffer(function() { return clickStream.throttle(250); })
    .map(function(list) { return list.length; })
    .filter(function(x) { return x > 1; });

// Same as above, but detects single clicks
var singleClickStream = clickStream
    .buffer(function() { return clickStream.throttle(250); })
    .map(function(list) { return list.length; })
    .filter(function(x) { return x === 1; });

// Listen to both streams and render the text label accordingly
singleClickStream.subscribe(function (event) {
    document.querySelector('h2').textContent = 'click';
});
multiClickStream.subscribe(function (numclicks) {
    document.querySelector('h2').textContent = ''+numclicks+'x click';
});
Rx.Observable.merge(singleClickStream, multiClickStream)
    .throttle(1000)
    .subscribe(function (suggestion) {
        document.querySelector('h2').textContent = '';
    });

clickStream序列在merge之后会迭代多少次? 我的意思是,它看起来像这样吗:

案例 1

     for(numclicks : clickStream.length){
        if (numclicks === 1){ 
            document.querySelector('h2').textContent = 'click';
        }
     };
     for(numclicks : clickStream.length){
        if (numclicks > 1){ 
            document.querySelector('h2').textContent = ''+numclicks+'x click';
        }
     };

或者它会在内部,真正合并成这样的东西(伪代码):

案例 2

    for(numclicks: clickStream.length){
        if (numclicks === 1){ 
            document.querySelector('h2').textContent = 'click';
        }else if(numclicks > 1){
            document.querySelector('h2').textContent = ''+numclicks+'x click';
        }
     }

我个人认为,合并只是顺序地将流应用于其参数(情况 1)。

P.S。我希望像这样的事情有一些标准。但如果不是——我对 RxCpp 和 Sodium 的实现特别感兴趣。 我以js为例,因为更具交互性。

fromEvent returns 一个 hot 源,因此所有订阅者共享相同的 for 循环迭代。

忽略油门调用,结果类似于:

for(numclicks: clickStream.length){

    // first subscription
    if (numclicks === 1){ 
        document.querySelector('h2').textContent = 'click';
    }

    // second subscription
    if(numclicks > 1){
        document.querySelector('h2').textContent = ''+numclicks+'x click';
    }

    // merged subscription
    if (numclicks === 0) {
        document.querySelector('h2').textContent = '';
    }
 }

throttle 调用意味着循环的唯一点击流主体实际上只是将点击事件推送到两个缓冲区并重置三个 throttle 运算符中每一个的计时器。当三个油门计时器之一触发时设置 h2。因为定时器不是共享的,所以它就像每个油门定时器一个单独的 for 循环,每个循环将 h2 设置为三个可能值中的一个:

此行为在所有 Rx 系列中都是相似的。

特别是关于 rxcpp:

rxcpp 缺少允许 observable 触发转换到新缓冲区的缓冲区重载。 rxcpp 还没有实现 throttle。 rxcpp 默认情况下不是线程安全的(按需付费),因此如果使用的节流计时器引入线程,则必须使用协调来显式添加线程安全。