Immutable Map – modyfikowanie wielu pól

Klasa Map z pakietu immutable jest obecnie popularnie wybierana jako kontener dla globalnego stanu w aplikacjach wykorzystujących redux.

Zauważyłem też że powszechną, ale błędną, praktyką jest modyfikowanie wielu pól przy pomocy łańcucha poleceń set.

const newState = oldState
    .set('field1', 'value1')
    .set('field2', 'value2')
    .set('field3', 'value3');

Podejście to sprawia, że za każdym wywołaniem metody set tworzona jest nowa, na szczęście płytka, kopia mapy ze zmienionym jednym polem.

Poprawę wydajności można uzyskać wykorzystując metodę withMutations.

const newState = oldState.withMutations(map => {
    map
    	.set('field1', 'value1')
        .set('field2', 'value2')
        .set('field3', 'value3');
    });

Mierz wyniki

Użycie tej metody nie gwarantuje jednak poprawy wydajności. Poniższy test zawiera 2 skraje przypadki użycia obu podejść:

const Map = require('immutable').Map;
const {
  performance
} = require('perf_hooks');

function test(tested) {
	const before = performance.now();
	for (let i = 0; i < 1000; i++) {
		tested();
	}
	return performance.now() - before;
}

let map = new Map();
const mapSet1 = test(function() {
	map.set("field1", "value");
});

map = new Map();
const mapWithMutations1 = test(function() {
	map.withMutations(map2 => {
		map2.set("field1", "value");
	})
});

map = new Map();
const mapSet2 = test(function() {
	map
		.set("field1", "value1")
		.set("field2", "value2")
		.set("field3", "value3")
		.set("field4", "value4")
		.set("field5", "value5")
		.set("field6", "value6")
		.set("field7", "value7")
		.set("field8", "value8")
		.set("field9", "value9");
});

map = new Map();
const mapWithMutations2 = test(function() {
	map.withMutations(map2 => {
		map2.set("field1", "value1");
		map2.set("field2", "value2");
		map2.set("field3", "value3");
		map2.set("field4", "value4");
		map2.set("field5", "value5");
		map2.set("field6", "value6");
		map2.set("field7", "value7");
		map2.set("field8", "value8");
		map2.set("field9", "value9");
	})
});

console.log({
	mapSet1,
	mapWithMutations1,
	mapSet2,
	mapWithMutations2
});

Na mojej maszynie uzyskałem następujący wynik:

{
  mapSet1: 0.9362990260124207,
  mapWithMutations1: 1.4729009866714478,
  mapSet2: 23.789600014686584,
  mapWithMutations2: 13.4621000289917
}

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *