Jusqu'à présent, la plupart des "starter boilerplates" et certains articles sur react / redux que j'ai vus encouragent l'utilisation de immuable.js pour traiter la mutabilité. Je m'appuie personnellement sur Object.assign
ou des opérateurs d'étalement pour gérer cela, donc je ne vois pas vraiment d'avantage dans immutable.js car il ajoute un apprentissage supplémentaire et s'écarte un peu des techniques js vanille utilisées pour la mutabilité. J'essayais de trouver des raisons valables pour un changement, mais je n'y suis pas parvenu ; c'est pourquoi je demande ici de voir pourquoi il est si populaire.
Réponses
Trop de publicités?C'est une question d'efficacité.
Structures de données persistantes
Une structure de données persistante conserve les versions précédentes d'elle-même lorsqu'elle est modifiée, en produisant toujours une nouvelle structure de données. Pour éviter un clonage coûteux, seule la différence avec la structure de données précédente est stockée, tandis que l'intersection est partagée entre elles. Cette stratégie est appelée partage structurel. Par conséquent, les structures de données persistantes sont beaucoup plus efficaces que le clonage. Object.assign
ou l'opérateur d'étalement.
Inconvénients des structures de données persistantes en Javascript
Malheureusement, Javascript ne supporte pas nativement les structures de données persistantes. C'est la raison pour laquelle immutable.js existe et que ses objets diffèrent grandement du vieux Javascript. Object
s. Cela conduit à un code plus verbeux et à de nombreuses conversions de structures de données persistantes en structures de données Javascript natives.
La question cruciale
Quand les avantages du partage structurel d'immutable.js (efficacité) dépassent-ils ses inconvénients (verbosité, conversions) ?
Je suppose que la bibliothèque n'est rentable que dans les grands projets comportant des objets et des collections nombreux et étendus, lorsque le clonage de structures de données entières et le ramassage des déchets deviennent plus coûteux.
J'ai créé les repères de performance pour plusieurs bibliothèques immuables, le script et les résultats se trouvent à l'intérieur du fichier immutable-assign (projet GitHub) ce qui montre que immuable.js est optimisé pour les opérations d'écriture, plus rapide que Object.assign(), mais il est plus lent pour les opérations de lecture. Voici le résumé des résultats des benchmarks :
-- 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.
Par conséquent, l'utilisation d'immutable.js ou non dépendra du type de votre application et de son rapport lecture/écriture. Si vous avez beaucoup d'opérations d'écriture, alors immutable.js sera une bonne option.
Idéalement, vous devriez établir le profil de votre application avant d'introduire toute optimisation des performances. Toutefois, l'immuabilité est l'une des décisions de conception qui doivent être prises tôt. Lorsque vous commencez à utiliser immuable.js En effet, l'interopérabilité avec les objets JS ordinaires à l'aide de fromJS() et toJS() est très coûteuse.
Je pense que le principal avantage d'ImmutableJs réside dans ses structures de données et sa vitesse. Bien sûr, il renforce également l'immutabilité, mais vous devriez le faire de toute façon, donc c'est juste un avantage supplémentaire.
Par exemple, disons que vous avez un très gros objet dans votre réducteur et que vous voulez modifier une toute petite partie de cet objet. En raison de l'immuabilité, vous ne pouvez pas modifier l'objet directement, mais vous devez créer une copie de l'objet. Pour ce faire, vous devez tout copier (dans ES6, vous utilisez l'opérateur spread).
Quel est le problème ? La copie de très gros objets est très lente. Les structures de données dans ImmutableJS font quelque chose appelé partage structurel où vous ne modifiez que les données que vous voulez. Les autres données que vous ne modifiez pas sont partagées entre les objets, elles ne sont donc pas copiées.
Il en résulte des structures de données très efficaces, avec des écritures rapides.
ImmutableJS offre également des comparaisons faciles pour les objets profonds. Par exemple
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
Sans cela, vous auriez besoin d'une sorte de fonction de comparaison profonde, qui prendrait également beaucoup de temps, alors que les nœuds Root contiennent ici un hash de l'ensemble de la structure de données (ne me citez pas, c'est comme ça que je m'en souviens, mais les comparaisons sont toujours instantanées), donc les comparaisons sont toujours O(1)
c'est-à-dire instantanée, quelle que soit la taille de l'objet.
Cela peut être particulièrement utile dans le cadre de React shouldComponentUpdate
où vous pouvez simplement comparer les accessoires en utilisant cette méthode. equals
qui s'exécute instantanément.
Bien sûr, il y a aussi des inconvénients, si vous mélangez des structures immuables et des objets ordinaires, il peut être difficile de faire la part des choses. De plus, votre base de code est jonchée de la syntaxe immutableJS, qui est différente du Javascript ordinaire.
Un autre inconvénient est que si vous n'utilisez pas d'objets profondément imbriqués, il sera un peu plus lent que le bon vieux js, puisque les structures de données ont une certaine surcharge.
Juste mes deux centimes.
L'avantage de immutable.js est qu'il met en application un magasin redux immuable (vous pourriez oublier de l'étendre, ou faire un travail bâclé pour protéger votre magasin contre les modifications) et simplifie les réducteurs beaucoup par rapport à Object.assign
ou des opérateurs d'écart (les deux sont peu profonds d'ailleurs !).
Cela dit, j'ai utilisé redux+immutable dans un gros projet Angular 1.x et il y a des inconvénients : problèmes de performance, il n'est pas clair ce qui est immuable et ce qui ne l'est pas, Angular ne peut pas utiliser les structures immuables.js dans ng-repeat
etc. Je ne suis pas sûr de React, mais j'aimerais connaître votre avis.
immuable.js vous donne beaucoup d'utilitaires qui retournent toujours un nouvel objet.
exemple :
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
Pour seulement react / redux je pense personnellement que Object.assign est assez puissant, mais dans certains cas l'utilisation de cette bibliothèque pourrait vous faire gagner quelques lignes de code.