I have a series of mutations to make on my Immutable.js map.
At what point should I prefer using withMutations
rather than creating intermediate immutable maps?
From the Immutable.js docs:
If you need to apply a series of mutations to produce a new immutable Map, withMutations() creates a temporary mutable copy of the Map which can apply mutations in a highly performant manner. In fact, this is exactly how complex mutations like merge are done.
But, where is the line? If I need to make two mutations should I use withMutations
?
js provides many Persistent Immutable data structures including: List , Stack , Map , OrderedMap , Set , OrderedSet and Record .
An Immutable Map is an unordered collection of key/value pairs that at first glance seems similar to a JavaScript object. However, it has the following additional properties: You can iterate over the keys of a Map.
Using ImmutableJS can improve dramatically the performance of your application. And, because the immutable data never changes, you can always expect new data to be passed from the above. To make sure you are correctly comparing the data and not updating the UI when there is no change, you should always use the .
Multiple iterations of the same Map will iterate in the same order. Map's keys can be of any type, and use Immutable.is to determine key equality.
You should use withMutations when you want to group several changes on an object.
Because each change creates a clone, several changes in a row cause several clones. Use withMutations to apply several changes then clone once at the end. A clone at every step means that you are reading the entire list for each change, which makes it an n^2 operation. Using the mutatable version leaves it at just N.
This can create a massive performance hit if you just start doing things willy nilly like the other answer suggests. The kicker is it might not matter on a small test of data, but what happens if you push it live and then do a large scale operation on an array with 300,000 pieces of data instead of your test data which only has 100 elements. In your test data, you did 10,000 copies of which you might not notice. In production you would do 900,000,000,00 copies which might light your computer on fire (not really, but you would freeze the tab).
I wrote a demo demonstrating the performance difference http://jsperf.com/with-out-mutatable
I've also been trying to decide when it's best to use withMutations vs not. So far I have always been using withMutations when I need to loop through a list of items with unknown size n
, and perform n
mutations on a single map. Example:
updateItems(state, items) { return state.withMutations(state => { items.forEach(item => { state.set(item.get('id'), item); }); }); }
What I wanted to know, is if I should use withMutations on a smaller known set of updates, or if I should just chain set
.
Example:
setItems(state, items, paging) { return state.set('items', items).set('paging', paging); }
Or:
setItems(state, items, paging) { return state.withMutations(state => { state.set('items', items); state.set('paging', paging); }); }
In this case, I would prefer to use the first option (chained set
calls), but I wasn't sure of the performance impact. I created this jsPerf to test some similar cases: http://jsperf.com/immutable-batch-updates-with-mutations.
I ran batches of 2 updates and 100 updates, using an empty inital map, and a complex initial map, both using withMutations
and just chaining set
.
The results seem to show that withMutations
was always better on the 100 update case, regardless of initial map. withMutations
performed marginally better on the 2 update case when starting with an empty map. However, just chaining 2 set
calls performed better when starting with a complex map.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With