immutablejs-presentation



immutablejs-presentation

0 0


immutablejs-presentation

https://xtuc.github.io/immutablejs-presentation

On Github xtuc / immutablejs-presentation

.js

"Immutable collections for JavaScript"

What the immuabilité ?

Ne peut pas être modifié une fois créé

Au cas ou certain ne savent pas ce que cela veut dire
Haskell
F#
Clojure (ImmutableJS s'en est inspiré)
Datomic
Event store
  • Dans le cas de F# on peut déclarer des variables avec le keywork mutable.
  • Datomic et event store sont des events store (des base de données immuable)

Rich Hickey

Les objets avec état muable sont le nouveau code spaghetti
  • C'est un problème de long date

Pourquoi ?

  • Plus facile à écrire et à comprendre
  • Partagez vos données en sécurité

Null Pointer Exception

var foo = { a: "a"};

setTimeout(() => {

    console.log(foo.a); // "a" ?

}, 1000);


var badFonction = () =>
    delete foo.a;
Je pensais que j'aurais "bar" dans foo lors de mon callback ...

Immutable.js

  • Les données sont immuables (immutable)
  • Une modification prend l'ancienne version et retourne une nouvelle version

Comme un problème

var foo = [1, 2, 3]
console.log(foo.length) // Output: 3

foo.length = 10
console.log(foo.length) // Output: 10
console.log(foo) // Output : [ 1, 2, , , , , , , ,  ]
Installation
npm i immutable
Usage
import Immutable from "Immutable";

const list         = Immutable.List();
const map          = Immutable.Map();
const stack        = Immutable.Stack();
const record       = Immutable.Record();
const seq          = Immutable.Seq();
const immutalbeObj = Immutable.fromJS({ … });
const obj          = myImmutalbeObj.toJS();
  • list = liste
  • map = Tableau associatif
  • stack = Tableau
  • record = classe (template)
  • seq = séquence de valeurs
  • fromjs = // Transforme un objet/tableau JS en Immutable List/Map, tojs = inverse

Liste

const foo = Immutable.List([
    "lundi",
        …
    "samedi",
    "dimanche"
]);
const bar  = foo.get(2) 
const foo2 = foo.push("samedi") 
const foo3 = foo.filter(x => x !== "lundi") 
const foo4 = foo.merge(foo²) 
const foo5 = foo.sort() 
Push, sort comme dans lib standart, filter sert a filtrer, merge merger, sort ordonner

Tableau associatif

const foo = Immutable.Map({
    lundi: "Mcdonald's",
        …
    vendredi: "Pizza",
    samedi: false,
    dimanche: false
});
const bar         = foo.get("jeudi") 
const foo1        = foo.set("samedi", "Pizza") 
const fooValues   = foo.values() 
const fooHasValue = foo.has("mardi") 
has() tester si la clé existe, values() retourne une liste des valeurs

Modifiez votre code

const user = { firstname: "Dennis", lastname: "Ritchie" };

const user1 = clone(user);

user1.firstname = "foo";

const user = Immutable.Map({
    firstname: "Dennis",
    lastname: "Ritchie"
});

const user1 = user.set("firstname", "foo");

Chainez vos transformations

const connectedUser = user
                        .filterNot((v, k) => k === "password")
                        .map(x => x.toUpperCase())
                        .set("foo", "bar")
                        .sort()
On peut chainer nos appels parce que chaque transformation returne une instance

Record

import Immutable from "immutable";

class HttpResponse extends Immutable.Record({
	statusCode: 200,
	content: "",
	headers: Immutable.Map()
}) {
	// Methodes de la classe	
}
const headers = Immutable.Map({ "Content-Type": "text/plain" });

const foo = new HttpResponse()
		.set("statusCode", 404)
		.set("content", "Page not found")
		.set("headers", headers);
C'est un template de class !
class HttpResponse extends Immutable.Record({
    statusCode: 200,
    content: "",
    headers: Immutable.Map()
}) {

    constructor(content = "", status = 200, headers = []) {

        return super({
            statusCode: status,
            content: content,
            headers: Immutable.Map(headers)
        });
    }
}
const headers = { "Content-Type": "text/plain" };
const foo = new HttpResponse("Page not found", 404, headers);
Un constructeur à été ajouté au record, la création de l'object reponse est simplifié. Record est aussi possible en es5. Valeur par défault dans le constructor es6 feature. Super fait appel au contructeur du parent

Structure de données comme type

class IPPacket extends Immutable.Record({
    Version: 4,
        …
    SourceAddress: null,
    DestinationAddress: null
}) {
    //
}

const packet = new IPPacket()
                    .set("Version", 6);

const data = packet.toJSON();

const packet = new IPPacket(data);
C'est pas clair, c'est comme une methode de sérialisation

Structure partagée

const xs = [a, b, c, d, f, g, h]

Représentation interne de xs

En anglais structural sharing
const xs = [a, b, c, d, f, g, h]
const ys = xs.push(e) // On crée l'élément "e" dans le tableau

ys est une copie supperficielle (shallow copy) de xs.

Gain de perfomarnce car c'est pas une copie complète

Modifications en lot

const foo = Immutable.List.of(1, 2, 3, 4);

const bar = foo.withMutations(mutable => {
	// mutable est une copy superficielle et temporaire de foo

    mutable
        .push(5)
        .push(6)
        .push(7);
});

// Array [1, 2, 3, 4, 5, 6, 7]
Batch modifications

Evaluation paresseuse (lazy evaluation)

const oddSquares = Immutable.List.of(1,2,3,4,5,6,7,8)
                                .filter(x => x % 2)
                                .map(x => x * x);

oddSquares.get(1); // 9
La racine caré ne sera calculer qu'une fois et sur un seul élément, le 1 dans ce cas.

L'immuabilité a un coût

Benchmark

jsperf.com (Chrome 48) Les opérations des bases sont plus lentes en Immutablejs

Copie (Lodash)

jsperf.com (Chrome 48) Il faut regarder les op/s. Lodash = underscore

Getter

jsperf.com (Chrome 48) L'écart de perf n'est pas affolant

Modifications en lot

jsperf.com (Chrome 48) le premier exemple fait deux copies au lieu d'une avec withMutations

Copie (Object assign)

jsperf.com (Chrome 48)

Questions ?

Read the docs and eat your vegetables Facebook

Elsass developer community

Rejoignez-nous sur Slack

Elsass-dev.fr

.js "Immutable collections for JavaScript"