2 个依赖流的安全更新 [英] Safe update for 2 dependent streams

查看:51
本文介绍了2 个依赖流的安全更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为练习,我正在尝试构建 2 个相互更新的依赖流.

测试应用程序只是一个英寸 <-> 厘米"转换器,两个输入都可编辑.

我遇到的问题是我无法停止导致一个字段更改的递归.

为了更好地解释这个问题,让我们看一下代码的相关部分:

var cmValue = new Rx.BehaviorSubject(0),inValue = new Rx.BehaviorSubject(0);# 处理程序 #1cmValue.distinctUntilChanged().subscribe(function(v) {inValue.onNext(cmToIn(v));});# 处理程序 #2inValue.distinctUntilChanged().subscribe(function (v) {cmValue.onNext(inToCm(v));});

所以我们给Subjects定义了每个持有当前对应值的对象.

现在假设我们将英寸值更改为 2(使用 inValue.onNext(2); 或通过键盘).

接下来会发生什么 - 处理程序 #2 被触发并调用相应的以厘米为单位的值的重新计算.结果为 cmValue.onNext(0.7874015748031495).

此调用实际上由处理程序 #1 处理,并使用 0.7874015748031495 * 2.54 公式重新计算以英寸为单位的值(我们手动放置的值),该公式导致另一个 inValue.onNext(1.99999999999999973) 调用.

幸运的是 - 由于 FP 舍入错误,这就是我们停止的地方.但在其他情况下,这可能会导致更多的循环甚至无限递归.

如您所见 - 我部分解决了应用 .distinctUntilChanged() 的问题,这至少可以保护我们免受任何更改的无限递归,但正如我们所看到的 - 在这种情况下它不是完全解决问题,因为值不相同(由于 FP 操作性质).

所以问题是:如何实现一个完全不会导致自递归的通用双向绑定?

我强调了通用性,以说明使用带有舍入的 .select() 将是针对此特定问题的部分解决方案,而不是通用性解决方案(我和其他所有人都更喜欢).

完整代码和演示:http://jsfiddle.net/ewr67eLr/

解决方案

在您的演示中,您有两个输入字段.此输入的Keyup"事件将是信息源,输入值将是目的地.在这种情况下,您不需要可变状态来检查 observable 的更新.

Rx.Observable.fromEvent(cmElement, 'keyup').map(目标值).distinctUntilChanged().map(cmToIn).startWith(0).subscribe(function(v){ inElement.value = v; });Rx.Observable.fromEvent(inElement, 'keyup').map(目标值).distinctUntilChanged().map(inToCm).startWith(0).subscribe(function(v){ cmElement.value = v; });

在这里查看我的示例:http://jsfiddle.net/537Lrcot/2/

As an exercise I'm trying to build 2 dependent streams which update one another.

The test application is simply an "Inches <-> Centimeters" converter, with both inputs editable.

The issue I am experiencing is that I cannot get how can I stop recursion that causes one field change.

To better explain the issue let's have a look at the relevant part of code:

var cmValue = new Rx.BehaviorSubject(0),
    inValue = new Rx.BehaviorSubject(0);

# handler #1
cmValue.distinctUntilChanged().subscribe(function(v) {
    inValue.onNext(cmToIn(v));
});

# handler #2
inValue.distinctUntilChanged().subscribe(function (v) {
    cmValue.onNext(inToCm(v));
});

So we define to Subjects each of which holds the current corresponding value.

Now imagine we change the value in inches to 2 (using inValue.onNext(2); or via keyboard).

What happens next - is the handler #2 is triggered and it invokes a corresponding recalculation of a value in centimeters. Which results to cmValue.onNext(0.7874015748031495).

This call in fact is then handled by handler #1 and causes the value in inches (the one we put manually) to be recalculated, using 0.7874015748031495 * 2.54 formula which causes another inValue.onNext(1.99999999999999973) call.

Luckily - due to FP rounding error that's where we stop. But in other scenarios this may lead to more loops or even to an infinite recursion.

As you can see - I partially solved the issue applying .distinctUntilChanged() which at least protects us from an infinite recursion on any change, but as we can see - in this case it's does not solve the problem entirely since values are not identical (due to FP operations nature).

So the question is: how would one implement a generic two-way binding that does not cause self-recursion at all?

I emphasized generic to make a note that using .select() with rounding would be a partial solution for this particular issue, and not the generic one (which I and everyone else would prefer).

The complete code and demo: http://jsfiddle.net/ewr67eLr/

解决方案

In your demo you have two input fields. "Keyup" events for this inputs will be the information source, and inputs value will be destination. In this case you don't need mutable states for checking updates of observables.

Rx.Observable.fromEvent(cmElement, 'keyup')
    .map(targetValue)
    .distinctUntilChanged()
    .map(cmToIn)
    .startWith(0)
    .subscribe(function(v){ inElement.value = v; });

Rx.Observable.fromEvent(inElement, 'keyup')
    .map(targetValue)
    .distinctUntilChanged()
    .map(inToCm)
    .startWith(0)
    .subscribe(function(v){ cmElement.value = v; });

Check my example here: http://jsfiddle.net/537Lrcot/2/

这篇关于2 个依赖流的安全更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆