演習として、互いに更新する 2 つの依存ストリームを構築しようとしています。
テスト アプリケーションは単純な "インチ <-> センチメートル" コンバーターであり、両方の入力が編集可能です。
私が経験している問題は、1 つのフィールドの変更を引き起こす再帰を停止する方法がわからないことです。
問題をよりよく説明するために、コードの関連部分を見てみましょう。
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));
});
そのため、それぞれが現在の対応する値を保持するサブジェクトを定義します。
ここで、インチ単位の値を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/