首页 文章

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

提问于
浏览
1

我正试图让我的第一个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列表中的更改;是否会使这个不可变的东西能够直接观察变化?或者这些东西只能从“顶层”检测到 .

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

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

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实际上发生了什么 . 我是否将整个数组中的每一项复制或映射到一个全新的数组/映射 - 每次我需要更改不可变集合中的某些内容?或者我只是改变一个参考或什么?

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

    但是,在性能关键的情况下,您可以使用一种策略,在该策略中,您只使用不可变的开发和测试构建来确保您的应用程序正常工作,而对于 生产环境 构建,您可以停用不变性以优化最后一点性能 .

相关问题