Redux / ImmutableJS嵌套状态+ Big-o不可变集合的复杂性

时间:2016-11-23 13:16:12

标签: typescript redux immutability ngrx immutable-collections

我试图了解我的第一个Redux(NGRX / Store)项目的Immutability。避免状态突变已经证明非常痛苦,在与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列表中的更改;是否会使这个不可变的东西能够直接观察变化?或者这些东西只能从顶部&#39;水平。

我想我的下一个问题是:我是否需要担心这一点。我已经明白,更改不可变集合是一项非常昂贵的操作。如果我做list.push或map.set实际上发生了什么事情。我是否将整个数组中的每一项复制或映射到一个全新的数组/映射 - 每次我需要更改不可变集合中的某些内容?或者我只是改变一个参考或什么?

我希望有一些关于不可变集合的Big-Oh复杂性的已发布信息,这将使它易于理解这些事情将如何执行,但我无法在任何地方找到它。

1 个答案:

答案 0 :(得分:1)

  

是否有任何意义在不变性中做不变性&#39;像这样?

对于大多数部分,非常原始的答案是:否。 - 对于变更检测的目的,如果一个对象是不可变的并不重要 - 但它确实有助于你强制执行始终创建一个新对象的概念,永远不要改变商店外的现有状态(甚至在减速器本身)。

  

我确实希望能够订阅ClosedCandles上的更改   列表;将使这个不可变的东西允许观察到的东西   直接改变?或者这些东西只能从顶部&#39;   水平。

是和否。直接观察变化可以通过设置直接选择instruments.ClosedCandles的流来实现 - 但这不是不可变性的特殊情况,这可以在有或没有不变性的情况下完成。

现在为了不变性和自上而下 -part:当你想要改变某个对象的某个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是什么   实际上发生在引擎盖下。我是否复制了每一件物品   整个数组或映射到一个全新的数组/地图一个接一个 -   每次我需要在不可变的集合中更改某些内容?要么   我只是更改参考或其他内容?

这主要取决于你如何使用不可变量,大多数库优化它并且还包装这些东西,所以你不必担心它。至于性能:在大多数情况下,它不会是一个大问题,大多数突变只会改变状态的一小部分,而状态的其余部分将只包含新的引用,通常不会创建新对象。

然而,在性能关键的情况下,您可以使用一种策略,其中您只使用不可变的开发和测试版本来确保您的应用程序正常工作,而对于生产构建,您可以停用不变性来优化甚至最后的性能。 / p>