web-dev-qa-db-fra.com

Pourquoi devrais-je utiliser immutablejs sur object.freeze?

J'ai fait des recherches sur net sur les avantages de immutablejs sur Object.freeze() mais je n'ai rien trouvé de satisfaisant!

Ma question est pourquoi je devrais utiliser cette bibliothèque et travailler avec des structures de données non natives quand je peux geler un vieil objet javascript ordinaire?

28
alisabzevari

Je ne pense pas que vous ayez compris ce que propose immutablejs. Ce n'est pas une bibliothèque qui transforme simplement vos objets immuables, c'est une bibliothèque autour du travail avec des valeurs immuables.

Sans simplement répéter leurs docs et mission statement , je vais énoncer deux choses qu'il fournit:

  1. Les types. Ils ont implémenté des gammes infinies (immuables), des piles, des ensembles ordonnés, des listes, ...

  2. Tous leurs types sont implémentés comme Structures de données persistantes .

J'ai menti, voici une citation de leur énoncé de mission:

Les données immuables ne peuvent pas être modifiées une fois créées, ce qui permet un développement d'applications beaucoup plus simple, aucune copie défensive et permet des techniques avancées de mémorisation et de détection des changements avec une logique simple. Les données persistantes présentent une API mutante qui ne met pas à jour les données sur place, mais génère toujours de nouvelles données mises à jour.

Je vous exhorte à lire les articles et vidéos auxquels ils renvoient et plus sur les structures de données persistantes (car ils sont la chose qui concerne immutablejs), mais je 'résumerai en une phrase ou deux:

Imaginons que vous écrivez un jeu et que vous avez un joueur assis dans un avion 2D. Voici, par exemple, Bob:

var player = {
  name: 'Bob',
  favouriteColor: 'moldy mustard',

  x: 4,
  y: 10
};

Puisque vous avez bu le FP koolaid vous voulez geler le joueur (brrr! J'espère que Bob a un pull)):

var player = Object.freeze({
    name: 'Bob',
    ...
});

Et maintenant, entrez dans votre boucle de jeu. A chaque tick, la position du joueur change. Nous ne pouvons pas simplement mettre à jour l'objet joueur car il est gelé, nous le copions donc:

function movePlayer(player, newX, newY) {
    return Object.freeze(Object.assign({}, player, { x: newX, y: newY }));
}

C'est bien et dandy, mais remarquez combien de copies inutiles que nous faisons: à chaque tick, nous créons un nouvel objet, itérons sur l'un de nos objets, puis attribuons de nouvelles valeurs par-dessus. A chaque tick, sur chacun de vos objets. C'est une bouchée.

Immutable résume cela pour vous:

var player = Immutable.Map({
    name: 'Bob',
    ...
});

function movePlayer(player, newX, newY) {
    return player.set('x', newX).set('y', newY);
}

Et à travers la ノ * ✧ ゚ magie ✧ ゚ * ヽ des structures de données persistantes, ils promettent de faire le moins d'opérations possibles.

Il y a aussi la différence des mentalités. Lorsque vous travaillez avec "un vieil objet javascript [figé]", les actions par défaut de tout consiste à assumer la mutabilité, et vous devez travailler mile supplémentaire pour atteindre une immuabilité significative (c'est-à-dire une immuabilité qui reconnaît que l'état existe). Cela fait partie de la raison pour laquelle freeze existe: lorsque vous essayez de faire autrement, les choses paniquent. Avec Immutablejs, l'immuabilité est, bien sûr, l'hypothèse par défaut et il y a une API Nice en plus.

Cela ne veut pas dire que tout est rose et rose avec de la cerise sur le dessus. Bien sûr, tout a ses inconvénients, et vous ne devriez pas entasser Immutable partout juste parce que vous le pouvez. Parfois, juste freezeing un objet est assez bon. Heck, la plupart du temps c'est plus qu'assez. C'est une bibliothèque utile qui a sa niche, ne vous laissez pas emporter par le battage médiatique.

50
Zirak

Selon mes benchmarks , immutable.js est optimisé pour les opérations d'écriture , plus rapide que Object.assign (), cependant, il est plus lent pour les opérations de lecture. La décision dépend donc du type de votre application et de son rapport lecture/écriture. Voici le résumé des résultats des benchmarks:

-- Mutable
Total elapsed = 103 ms = 50 ms (read) + 53 ms (write).

-- Immutable (Object.assign)
Total elapsed = 2199 ms = 50 ms (read) + 2149 ms (write).

-- Immutable (immutable.js)
Total elapsed = 1690 ms = 638 ms (read) + 1052 ms (write).

-- Immutable (seamless-immutable)
Total elapsed = 91333 ms = 31 ms (read) + 91302 ms (write).

-- Immutable (immutable-assign (created by me))
Total elapsed = 2223 ms = 50 ms (read) + 2173 ms (write).

Idéalement, vous devez profiler votre application avant d'introduire une optimisation des performances, cependant, l'immuabilité est l'une de ces décisions de conception qui doit être décidée tôt. Lorsque vous commencez à utiliser immutable.js , vous devez l'utiliser dans l'ensemble de votre application pour obtenir des avantages en termes de performances, car l'interopérabilité avec des objets JS simples à l'aide de fromJS () et toJS () est très coûteuse.

PS: Je viens de découvrir que le tableau Deep Freeze (1000 éléments) devient très lent à mettre à jour, environ 50 fois plus lentement, donc vous ne devez utiliser Deep Freeze qu'en mode développement. Résultats des benchmarks:

-- Immutable (Object.assign) + deep freeze
Total elapsed = 45903 ms = 96 ms (read) + 45807 ms (write).
6
engineforce

Les deux ne rendent pas l'objet profondément immuable.

Cependant, en utilisant Object.freeze vous devrez créer vous-même les nouvelles instances de l'objet/tableau, et elles n'auront pas de partage structurel. Donc, chaque changement qui nécessitera de tout copier en profondeur, et l'ancienne collection sera récupérée.

immutablejs d'autre part gérera les collections, et quand quelque chose change, la nouvelle instance utilisera les parties de l'ancienne instance qui n'ont pas changé, donc moins de copie et de ramasse-miettes.

4
Ori Drori

La principale raison qui vient à l'esprit - en dehors d'avoir une API fonctionnelle qui aide aux mises à jour immuables, est le partage structurel utilisé par Immutable.js. Si vous avez une application qui nécessite une immuabilité forcée (c'est-à-dire que vous utilisez Redux), si vous utilisez uniquement Object.freeze, vous allez faire une copie pour chaque "mutation". Ce n'est pas vraiment efficace au fil du temps, car cela conduira à un dépassement de GC. Avec Immutable.js, vous obtenez un partage structurel intégré (au lieu d'avoir à implémenter un pool d'objets/un modèle de partage structurel de votre choix) car les structures de données renvoyées par immuable sont des essais. Cela signifie que toutes les mutations sont toujours référencées dans la structure de données, de sorte que le thrashing GC est réduit au minimum. Plus d'informations à ce sujet sont sur le site de documentation d'Immutable.js (et une excellente vidéo plus approfondie du créateur, Lee Byron):

https://facebook.github.io/immutable-js/

1
Geoffrey Abdallah

Object.freeze ne fait pas de surgélation nativement, je crois que immutable.js le fait.

La même chose avec n'importe quelle bibliothèque - pourquoi utiliser le soulignement, jquery, etc.

Les gens aiment réutiliser les roues que d'autres ont construites :-)

1
Tuvia

Il existe quelques différences majeures entre Object.freeze () et immutable.js.

Abordons d'abord le coût des performances. Object.freeze () est superficiel. Cela rendra l'objet immuable, mais les propriétés et méthodes imbriquées à l'intérieur dudit objet peuvent toujours être mutées. La documentation Object.freeze () résout ce problème et continue même à fournir une fonction "deepFreeze", qui est encore plus coûteuse en termes de performances. Immutable.js en revanche rendra l'objet dans son ensemble (propriétés imbriquées, méthode, etc.) immuable à moindre coût.

De plus, si jamais vous avez besoin de cloner une variable immuable, Object.freeze () vous forcera à créer une variable entièrement nouvelle, tandis que Immutable.js peut réutiliser la variable immuable existante pour créer le clone plus efficacement. Voici une citation intéressante à ce sujet de cet article :

"Les méthodes immuables telles que .set () peuvent être plus efficaces que le clonage car elles permettent aux nouvelles données de référence d'objet dans l'ancien objet: seules les propriétés modifiées diffèrent. De cette façon, vous pouvez économiser de la mémoire et des performances par rapport à tout ce qui est constamment cloné en profondeur."

En un mot, Immutable.js établit des connexions logiques entre les anciennes et les nouvelles variables immuables, améliorant ainsi les performances de clonage et les variables d'espace gelées en mémoire. Object.freeze () ne le fait malheureusement pas - chaque fois que vous clonez une nouvelle variable à partir d'un objet figé, vous écrivez à nouveau toutes les données, et il n'y a pas de connexion logique entre les deux variables immuables même si (pour une raison étrange) elles sont identiques Les données.

Donc, en termes de performances, surtout si vous utilisez constamment des variables immuables dans votre programme, Immutable.js est un excellent choix. Cependant, les performances ne sont pas tout et il y a de grandes mises en garde à utiliser Immutable.js. Immutable.js utilise sa propre structure de données, ce qui rend le débogage, ou même simplement la journalisation des données sur la console, une douleur royale. Cela peut également entraîner une perte des fonctionnalités JavaScript de base (par exemple, vous ne pouvez pas utiliser la déstructuration ES6 avec elle ) La documentation Immutable.js est tristement impossible à comprendre (car elle a été initialement écrite pour être utilisée uniquement au sein de Facebook lui-même), ce qui nécessite de nombreuses recherches sur le Web, même lorsque de simples problèmes surviennent.

J'espère que cela couvre les aspects les plus importants des deux approches et vous aide à décider lequel vous conviendra le mieux.

1
Nadav