1

最初の Redux (NGRX/Store) プロジェクトの不変性について頭を悩ませようとしています。状態の変更を回避することは非常に困難であることがわかりました。Object.assign({}) と状態の変更エラーと戦った後、Immutable.JS を発見しました。これにより、物事がはるかに簡単になります。

私が金融取引アプリケーションを持っているとしましょう。ロード時にチャートにバーのコレクションを表示する必要があります。毎秒数回、ライブ価格情報に基づいて最後のバーを更新する必要があり、そのたびに新しいバーが追加されます。

そして、これはすべて {1-n} 金融商品 (EURUSD/GBPJPY/Gold/Oil など) に対して発生する必要があります。だから私は私のアプリのこの部分のためにこのモデルを思いつきました:

export interface CandleState {
  LastCompletedCandle : Candle;
  InProgressCandle : Candle;
  LastTick:Offer;
  ClosedCandles:immutable.List<Candle>;
};

export interface AllCandleState {
   instruments: immutable.Map<string, CandleState>
}

不変リストを含む不変マップがあることに気付くでしょう。したがって、私の最初の質問は次のとおりです。このように「不変性内の不変性」を行うことに何か意味はありますか? 電話してから

instruments.set("EURUSD", { [my new state] })

まったく新しい状態を効果的に返すため、このように不変性をネストする必要があるかどうかはわかりません.... ClosedCandlesリストの変更を購読できるようにしたいです。これを不変にすることで、変更を直接観察できるようになりますか? または、これらは「トップ」レベルからのみ検出されます。

私の次の質問は、これについてまったく心配する必要があるかどうかです。不変のコレクションを変更することは非常にコストのかかる操作であることが頭に浮かびました。list.push または map.set を実行すると、内部で実際に何が起こっているかがわかります。不変コレクションで何かを変更する必要があるたびに、配列全体またはマップ内のすべてのアイテムを新しい配列/マップに 1 つずつコピーしていますか? それとも、参照か何かを変更しているだけですか?

これらがどのように実行されるかを簡単に理解できるように、不変コレクションの Big-Oh Complexity に関する公開情報があればいいのですが、どこにも見つかりません。

4

1 に答える 1

1

このように「不変性内の不変性」を行うことに何か意味はありますか?

ほとんどの場合、非常に原始的な答えは次のとおりです。いいえ。-変更検出の目的では、オブジェクトが不変であるかどうかは問題ではありません-ただし、常に新しいオブジェクトを作成し、既存の状態を決して変更しないという概念を強制するのに役立ちますストアの外(およびレデューサー自体でも)。

ClosedCandles リストの変更を購読できるようにしたいです。これを不変にすることで、変更を直接観察できるようになりますか? または、これらは「トップ」レベルからのみ検出されます。

はいといいえ。変更を直接観察することは、直接選択するストリームを設定することで実現できますがinstruments.ClosedCandles、これは不変性の特別なケースではなく、不変性の有無にかかわらず行うことができます。

不変性とトップダウンの部分について: オブジェクトの n レベル下の何かを変更したい場合、変更されたオブジェクトのすべての親 (ルートまで) を単純に再作成する必要があることが常にあります。不変の場合、親を変更できないため、新しい参照を設定することはできません。

例:

root                <-- to enable changing the map1, you have to recreate the root, since it is immutable
|--map1             <-- to enable changing the set2, you have to recreate this map, since it is immutable
|  |--set1          <-- untouched, the "new version" of map1 will reference the same "set1"
|  \--set2          <-- to enable changing the attribute2, you have to recreate this set, since it is also immutable
|     |--attribute1 <-- untouched, the "new version" of set2 will just have the same reference on this object as the "old version"
|     \--attribute2 <-- you want to alter this attribute
|
|--map2             <-- untouched, the "new version" of root will reference the same "map2"
\--map3             <-- untouched, the "new version" of root will reference the same "map3"

私の次の質問は、これについてまったく心配する必要があるかどうかです。不変のコレクションを変更することは非常にコストのかかる操作であることが頭に浮かびました。list.push または map.set を実行すると、内部で実際に何が起こっているかがわかります。不変コレクションで何かを変更する必要があるたびに、配列全体またはマップ内のすべてのアイテムを新しい配列/マップに 1 つずつコピーしていますか? それとも、参照か何かを変更しているだけですか?

これは主に、不変の使用方法に依存します。ほとんどのライブラリはこれを最適化し、このようなものをラップするため、心配する必要はありません。パフォーマンスに関して: ほとんどの場合、大したことではありません。ほとんどのミューテーションは状態の小さな部分のみを変更し、状態の残りの部分は新しい参照で構成され、通常は新しいオブジェクトは作成されません。

ただし、パフォーマンスが重要なケースでは、開発ビルドとテスト ビルドにのみ不変を使用してアプリケーションが正しく動作することを確認し、運用ビルドでは不変性を非アクティブ化してパフォーマンスの最後のビットでも最適化するという戦略を使用できます。

于 2016-11-24T13:17:37.903 に答える