web-dev-qa-db-ja.com

Object.assignまたはspread演算子よりもimmutable.jsを使用する利点

これまでのところ、「スターターボイラープレート」のほとんどと、反応/リデュースに関するいくつかの投稿は、可変性に対処するために immutable.js の使用を推奨しています。私は個人的にObject.assignまたはスプレッド演算子を使用してこれを処理します。したがって、immutable.jsには利点がありません。追加の学習が追加され、可変性に使用されるVanilla jsテクニックから少しシフトします。私は切り替えの正当な理由を見つけようとしていましたが、それができなかったので、なぜそれがそんなに人気があるのか​​をここで尋ねています。

28
Ilja

これはすべて効率に関するものです。

永続的なデータ構造

永続的なデータ構造は、常に新しいデータ構造を生成することによって変更されたときに、それ自体の以前のバージョンを保持します。高価なクローン作成を避けるために、前のデータ構造との違いのみが保存され、交差はそれらの間で共有されます。この戦略は、構造共有と呼ばれます。したがって、永続データ構造は、Object.assignまたはスプレッド演算子を使用してクローンを作成するよりもはるかに効率的です。

Javascriptの永続データ構造の欠点

残念ながら、Javascriptは永続的なデータ構造をネイティブにサポートしていません。それがimmutable.jsが存在する理由であり、そのオブジェクトは単純な古いJavascript Objectsとは大きく異なります。これにより、より冗長なコードが生成され、永続的なデータ構造からネイティブなJavaScriptデータ構造への多くの変換が行われます。

重要な質問

Immutable.jsの構造的な共有(効率)の利点が、その欠点(冗長性、変換)を超えるのはいつですか?

ライブラリは、データ構造全体とガベージコレクションのクローン作成がより高価になる場合に、多数の広範なオブジェクトとコレクションを持つ大規模プロジェクトでのみ成果を上げると思います。

32
user6445533

複数の不変ライブラリのパフォーマンスベンチマークを作成しました。スクリプトと結果は immutable-assign(GitHubプロジェクト) 内にあり、 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が適切なオプションになります。

早すぎる最適化はすべての悪の根源です

理想的には、パフォーマンスの最適化を導入する前にアプリケーションをプロファイルする必要がありますが、不変性は設計上の決定の1つであり、早期に決定する必要があります。 immutable.js の使用を開始する場合、fromJS()およびtoJS()を使用したプレーンJSオブジェクトとの相互運用は非常にコストがかかるため、アプリケーション全体で使用してパフォーマンス上のメリットを得る必要があります。

15
engineforce

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構造と通常のオブジェクトを混在させると、何が何であるかを判断するのが難しくなります。また、コードベースには、通常のJavascriptとは異なるimmutableJS構文が散らばっています。

別の欠点は、深くネストされたオブジェクトを使用しない場合、データ構造にいくらかのオーバーヘッドがあるため、単純な古いjsよりも少し遅くなることです。

ちょうど私の2セント。

3
Pavlin

Immutable.jsの利点は、enforces不変のreduxストア(拡張するのを忘れるか、変更からストアを保護するためにずさんな仕事をする)とsimplifiesObject.assignまたはスプレッド演算子(両方ともちなみに浅い!)と比較して、多くのリデューサー。

それは、大きなAngular 1.xプロジェクトでredux + immutableを使用しており、欠点があります:パフォーマンスの問題、不変のものとそうでないもの、Angularはng-repeatなどでimmutable.js構造を使用できません。Reactについてはわかりませんが、意見を聞きたいと思います。

2
Oleg

永続的なデータ構造によるパフォーマンスの向上だけではありません。不変性は、偶発的な変異によって引き起こされるバグを完全に排除するため、それ自体が非常に望ましい品質です。さらに、便利なJavascriptのAPIを備えた健全なデータ構造(実際に使用できるもの)があり、immutable.jsは、最近追加されたES6およびES7でも、vanilllaオブジェクトと配列よりもはるかに優れています。それはjQueryのようなものです-Vanilla DOM API(これは悪夢です)と比較してAPIが本当に優れていて使いやすいので、とても人気があります。もちろん、バニラオブジェクトで不変にとどまることはできますが、Object.assignと配列スプレッドを毎回忘れずに忘れないでください。immutable.jsを使えば、間違いを起こすことはできません。

1
Dr.Strangelove

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

ただのリアクション/リドゥのために、私はObject.assignが十分に強力であると個人的に思いますが、場合によってはそのライブラリを使用することで数行のコードを節約できます。

1
Alomsimoy