2016-11-23 73 views
1

我试图让我的头绕着我的第一个Redux(NGRX/Store)项目的不变性。避免状态变异已经证明是非常痛苦的,在与Object.assign({})和状态变异错误作斗争之后,我发现了Immutable.JS。这使事情变得更容易。Redux/ImmutableJS嵌套状态+ Big-o不可变集合的复杂性

可以说我有一个金融交易应用程序,它需要在加载时在图表上显示一个酒吧集合。每秒钟几次,最后一根酒吧需要根据实时价格信息进行更新,而且每隔一段时间都会增加一个新酒吧。

这一切都需要为{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实际发生的事情。我是否将整个数组或地图中的每个项目都复制到一个全新的数组/地图中 - 每次我需要在不可变集合中更改某些内容时?或者我只是改变一个参考或其他东西?

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

回答

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什么是 实际上发生在引擎盖下。我是否每次需要在不可变的集合中更改某个东西时,将整个数组或地图中的每个项目都复制到一个全新的数组/地图中? ?或者 我只是在改变一个参考或其他东西?

这主要取决于你如何使用immutables,大多数库优化这个,也包装这个东西,所以你不必担心它。至于表现:在大多数情况下,这不会是什么大问题,大多数突变只会改变小部分状态,其余状态只会包含新引用,通常不会创建新对象。

但是,在性能关键的情况下,您可以使用一种策略,只使用不可变的开发和测试版本来确保您的应用程序正常工作,并且对于生产而言,您可以停用不变性来优化性能的最后一点。