【问题标题】:Advantages of using immutable.js over Object.assign or spread operators使用 immutable.js 优于 Object.assign 或传播运算符的优势
【发布时间】:2017-01-06 18:12:31
【问题描述】:

到目前为止,我看到的大多数“入门样板”和一些关于 react/redux 的帖子都鼓励使用 immutable.js 来解决可变性问题。我个人依靠Object.assign 或传播运算符来处理这个问题,因此在 immutable.js 中并没有真正看到优势,因为它增加了额外的学习,并且从用于可变性的 vanilla js 技术有所改变。我试图找到切换的正当理由,但无法找到,因此我在这里询问它为什么如此受欢迎。

【问题讨论】:

    标签: javascript reactjs redux immutability


    【解决方案1】:

    这都是关于效率的。

    持久数据结构

    持久性数据结构在通过始终产生新数据结构而发生突变时会保留其先前版本。为了避免昂贵的克隆,只存储与先前数据结构的差异,而交集在它们之间共享。这种策略称为结构共享。因此,持久性数据结构比使用Object.assign 或扩展运算符克隆要高效得多。

    Javascript 中持久数据结构的缺点

    不幸的是,Javascript 本身不支持持久数据结构。这就是 immutable.js 存在的原因,它的对象与普通的旧 Javascript Objects 有很大不同。这会导致代码更加冗长,并且需要大量将持久性数据结构转换为原生 Javascript 数据结构。

    关键问题

    immutable.js 的结构共享(效率)的好处何时超过其缺点(冗长、转换)?

    我猜这个库只有在包含大量对象和集合的大型项目中才能得到回报,因为克隆整个数据结构和垃圾收集变得更加昂贵。

    【讨论】:

    • 感谢您的回答,但请像向愚蠢的人一样向我解释。到目前为止,我了解Immutable.js 使用持久数据结构来存储未更改的原始数组或对象的部分。但是你还是要给变量赋值不变的部分和改变的部分,那怎么比Object.assign()或者array.slice()效率高呢? Immutable.js 执行了哪些内部操作以减少内存使用量?
    【解决方案2】:

    我已经为多个不可变库创建了性能基准,脚本和结果位于immutable-assign (GitHub project) 内,这表明immutable.js 针对写操作进行了优化,比 Object.assign() 快,但是,它是读取操作较慢。以下是基准测试结果的摘要:

    -- Mutable
    Total elapsed = 50 ms (read) + 53 ms (write) = 103 ms.
    
    -- Immutable (Object.assign)
    Total elapsed = 50 ms (read) + 2149 ms (write) = 2199 ms.
    
    -- Immutable (immutable.js)
    Total elapsed = 638 ms (read) + 1052 ms (write) = 1690 ms.
    
    -- Immutable (seamless-immutable)
    Total elapsed = 31 ms (read) + 91302 ms (write) = 91333 ms.
    
    -- Immutable (immutable-assign (created by me))
    Total elapsed = 50 ms (read) + 2173 ms (write) = 2223 ms.
    

    因此,是否使用 immutable.js 将取决于您的应用程序的类型,以及它的读写比率。如果你有很多写操作,那么 immutable.js 将是一个不错的选择。

    Premature optimization is the root of all evil

    理想情况下,您应该在引入任何性能优化之前分析您的应用程序,但是,不变性是必须及早决定的设计决策之一。当您开始使用 immutable.js 时,您需要在整个应用程序中使用它以获得性能优势,因为使用 fromJS() 和 toJS() 与普通 JS 对象进行互操作非常昂贵。

    【讨论】:

      【解决方案3】:

      我认为 ImmutableJs 的主要优势在于它的数据结构和速度。当然,它还强制执行不变性,但无论如何你都应该这样做,所以这只是一个额外的好处。

      例如,假设您的减速器中有一个非常大的对象,并且您想更改该对象的一小部分。由于不可变性,您不能直接更改对象,但必须创建对象的副本。您可以通过复制所有内容来做到这一点(在 ES6 中使用扩展运算符)。

      那么问题是什么?复制非常大的对象非常慢。 ImmutableJS 中的数据结构做了一种叫做结构共享的事情,你实际上只改变你想要的数据。您未更改的其他数据在对象之间共享,因此不会被复制。

      这样做的结果是高效的数据结构,写入速度快。

      ImmutableJS 还为深层对象提供了简单的比较。例如

      const a = Immutable.Map({ a: Immutable.Map({ a: 'a', b: 'b'}), b: 'b'});
      const b = Immutable.Map({ a: Immutable.Map({ a: 'a', b: 'b'}), b: 'b'});
      
      console.log(a.equals(b)) // true 
      

      没有这个,你需要某种深度比较函数,这也需要很多时间,而这里的根节点包含整个数据结构的哈希(不要引用我的话,这就是我记得,但比较总是即时的),所以比较总是O(1) 即即时,无论对象大小。

      这在 React shouldComponentUpdate 方法中特别有用,您可以使用这个即时运行的 equals 函数来比较道具。

      当然,也有缺点,如果你将 immutablejs 结构和常规对象混合在一起,可能很难分辨出什么是什么。此外,您的代码库中充斥着 immutableJS 语法,这与常规 Javascript 不同。

      另一个缺点是,如果你不打算使用深度嵌套的对象,它会比普通的旧 js 慢一点,因为数据结构确实有一些开销。

      只要我的 2 美分。

      【讨论】:

      • 不会使用扩展运算符(Object.assign)进行浅拷贝吗?就像我希望let obj = {listWith200MillionsObjects: [...], username: 'Kevin'}; let newObj= {...obj, username: 'Pavlin'}; 只复制对 2 亿个对象列表的引用,而不是复制每个 2 亿个对象?而且为了比较,它也不会很快起作用吗? obj == newObj 会返回 false 因为它是两个不同的对象,所以只是指针比较?尽管let newObj2 = {...obj}; 会使newObj2 == obj 返回false,即使它们包含相同的数据。
      【解决方案4】:

      immutable.js 的优势在于它强制一个不可变的 redux 存储(您可能忘记扩展,或者在保护存储免于修改方面做得草率)并且简化了 strong> 与 Object.assign 或扩展运算符相比,reducers 很多(顺便说一句,两者都很浅!)。

      话虽如此,我在一个大型 Angular 1.x 项目中使用了 redux+immutable,但也有缺点:性能问题,不清楚什么是不可变的,什么不是,Angular 不能在 @987654324 中使用 immutable.js 结构@ 等。虽然不确定 React,但很想听听意见。

      【讨论】:

      • 您还可以使用Object.freeze()deep-freeze 强制纯JS 对象的不变性
      • @engineforce seamless-immutable 正是这样做的。但在生产版本中,他们将其关闭。
      【解决方案5】:

      immutable.js 为您提供了许多总是返回新对象的实用程序。

      示例:

      var Immutable = require('immutable');
      var map1 = Immutable.Map({a:1, b:2, c:3});
      var map2 = map1.set('b', 50);
      map1.get('b'); // 2
      map2.get('b'); // 50
      

      对于 react/redux 我个人认为 Object.assign 足够强大,但在某些情况下使用该库可以为您节省几行代码。

      【讨论】:

        【解决方案6】:

        这不仅仅是通过持久数据结构来提高性能。不变性本身就是非常理想的品质,因为它完全消除了由意外突变引起的任何错误。另外,很高兴在 Javascript 中使用方便的 API 拥有健全的数据结构,这是实际可用的东西,而且 immutable.js 远远领先于 vanillla 对象和数组,即使最近添加了 ES6 和 ES7。它就像 jQuery - 它之所以如此受欢迎,是因为它的 API 与 vanilla DOM API 相比非常棒且易于使用(这只是一场噩梦)。当然,你可以尝试使用 vanilla 对象保持不可变,但是你不必忘记 Object.assign 和数组传播每个 FREAKING TIME,并且使用 immutable.js 你根本不会出错,这里的任何突变都是明确的

        【讨论】:

          猜你喜欢
          • 2016-09-27
          • 2019-04-25
          • 2013-09-17
          • 1970-01-01
          • 2015-04-02
          • 2018-07-17
          • 1970-01-01
          • 2012-04-20
          • 2011-03-27
          相关资源
          最近更新 更多