RxJS相当于带有属性的`Bacon.when()`(被采样但不是同步模式的一部分)

时间:2015-01-26 15:46:37

标签: javascript frp rxjs bacon.js

考虑以下Bacon.js代码示例(松散地基于the code here,使用bacon.model& bacon.jquery):

<input id="total" type="text" placeholder="total">
/
<input id="quantity" type="text" placeholder="quantity" value="1">
=
<span id="price"></span>
<script>

  var $total = Bacon.$.textFieldValue($("#total")).changes();

  var quantity = Bacon.$.textFieldValue($("#quantity"));

  var price = Bacon.when(
    [$total, quantity], function(x,y) { return x/y; }
  ).toProperty(0);

  price.onValue(function (p) {
    $('#price').text(p);
  });

</script>

此处发生的是,流$total和属性quantity已合并到属性price中。 $totalquantity都会从文本输入字段中获取输入,但只有$total会提示price进行更新。 (即quantity被采样但不是同步模式的一部分。)

我正在尝试使用RxJS而不是Bacon.js来实现同样的行为,但我能想到的只是超级丑陋的解决方案。我估计我必须忽略一些事情......?

到目前为止我最好的拍摄(行为不一样,但你明白了):

var totalChange = Rx.Observable.fromEvent($('#total'), 'input');

var totalValue = totalChange.map(function () {
  return parseInt($('#total').val(), 10);
});
var quantityValue = totalChange.map(function () {
  return parseInt($('#quantity').val(), 10);
});

var price = Rx.Observable.zip(
  totalValue,
  quantityValue,
  function (x,y) {
    return x/y;
  }
);

price.subscribe(function (p) {
  $('#price').text(p);
});

因为combineLatestzip都没有在直接表示两个文本字段的observable上提供所需的行为,所以我能想到的是根据文本字段中的输入事件创建数量的可观察量总计。哪个有效,但感觉相当牵强。

有关替代方法的任何建议吗?

3 个答案:

答案 0 :(得分:6)

使用最近添加的withLatestFrom代替combineLatest

var price = totalValue.withLatestFrom(quantityValue, (x,y) => x/y);

比较他们的图表:

答案 1 :(得分:1)

编辑:combineLatest似乎相当于培根的时间。

我想也许你想做这样的事情?

var totalChange = Rx.Observable.fromEvent($('#total'), 'input');

var totalValue = totalChange.map(function () {
  return parseInt($('#total').val(), 10);
});

var quantityValue = totalChange.map(function () {
  return parseInt($('#quantity').val(), 10);
});

Observable.combineLatest(totalValue, quantityValue, function(total, quantity) {
  return total / quantity;
});

不幸的是,这是我能想到的最漂亮的回答你问题精神的事情。

实际上,在这个例子中,您只需这样做:

var price = totalChange.map(function() {
  return parseInt($('#total').val(), 10) / parseInt($('#quantity').val(), 10);
});

答案 2 :(得分:0)

编辑:我刚刚意识到这个解决方案是Ben Lesh的答案的底部。我会把这个留在这里仅仅是为了更加冗长的解释。

如果一个变量不是被动的,有时候最简单的解决办法就是承认它而不是试图对它做出反应。

由于quantity不可观察,因此任何使其可观察并将两个可观察流组合在一起的尝试都会感到束缚。

相反,我只是接受它的不可观察性,并在map更改时使用total来阅读它:

var totalChange = Rx.Observable.fromEvent($('#total'), 'input');

var totalValue = totalChange.map(function () {
  return parseInt($('#total').val(), 10);
});

var price = totalValue.map(function (total) {
    var quantity = parseInt($('#quantity').val(), 10);
    return total / quantity;
});

price.subscribe(function (p) {
  $('#price').text(p);
});

// or, more succinctly with a single map operation:
var totalChange = Rx.Observable.fromEvent($('#total'), 'input');
var price = totalChange.map(function () {
    var total = parseInt($('#total').val(), 10);
    var quantity = parseInt($('#quantity').val(), 10);
    return total / quantity;
});
price.subscribe(function (p) {
  $('#price').text(p);
});