Doesn't Immutability Come at the Cost of Speed? - javascript

I don't know why I can't find an answer to this, but, with state managers requiring immutability, doesn't this come at a significant performance slowdown for large states? I am building an app for fun that wouldn't have arrays large enough to cause a problem (n would max out around a thousand or so, maybe, in extreme cases, a couple thousand).
But, lets say that the app had to keep a gigantic store of information in memory for some reason in state. Every time you have to edit one object, that would mean you have to completely reconstruct the array.
I'm just thinking that, maybe in the future I would need to have states that store such an amount of data, although I can't necessarily think of a concrete example where you would require a state manager to handle it for you. I'm just curious, is there any example where this weird hypothetical of having a huge state happens.
On a side note, the only reference I could find of immutability affecting speed is in increasing it, but this was on the note of reference equality being used for comparison. But wouldn't mutating data have nothing to do with whether you can compare the reference of the object or not?

You're misunderstanding how immutable updates work.
A correct immutable update doesn't require deep-cloning all objects. It's more like a nested shallow clone. Only the set of objects that actually have to be updated get copied, not all of them.
If I want to update state.items[5].completed, I need to make a copy of the item object at index 5, the items array, and state. All the other objects in the items array, and all the other sections of state, remain untouched.
There certainly is some amount of cost to copying those objects, but for the most part it's not meaningful unless they're exceptionally large.

Related

In Javascript, when an element of a large array is used multiple times, is it better to assign it to an other element?

I have to reach a value (direct access) many times in a very large 2D array. Is it better to assign a temporary variable or should I use the array[req.params.position.x][req.params.position.y].anyValue every time?
I know the "new variable" option would make it easier to look at it, I was wondering if that would make an impact on the performance of the code.
My hypothesis is that it acts as some kind of forEach in a forEach and thus takes more time to reach it every time.. ?
From your description array[req.params.position.x][req.params.position.y], it sounds like that whilst this is a 2D array, you also know up front the indexes of each array. This is direct access to the array which is extremely quick. It would be different if you needed to search for something in the array, but here you aren't needing that.
Internally, in browsers, this will be constant time access no matter how big the array is. It does not need to "lookup", since the passed indexes will reference the value location in memory -- where it will be retrieved directly.
So there is no performance concern here.

Is it more performant to transform arrays into objects and then manipulating with objects instead of arrays?

I am a web developer mostly using ReactJs and so far whenever I had a "list" of data I stored them in an array, but every time I had to modify or delete an item of the array I had to do like .filter() or .map() which normally goes through all the list and it's really unnecessary if I am removing or modifying just an item so I thought of using Objects,
if I get some data like:
[
{ id: 1, name: "Tony" },
{ id: 2, name: "Toad" },
{ id: 3, name: "Gon" }
];
I turn it into an object like:
const object = {};
[
{ id: 1, name: "Tony" },
{ id: 2, name: "Toad" },
{ id: 3, name: "Gon" }
].forEach((item) => (object[item.id] = item));
And since the id I know that will always be unique when I have to delete an element I can just say delete object["some key"], or if I have to modify I can say object["some key"]= modifiedItem. I've worked only on few projects done by other people but never really saw someone going like this. I am wondering is it worth to go this approach?
There is one downside to this that I can think of, if I want to render the items I would have to do Object.keys(object).map(key=>(<div>{object[key].name}</div>)) as if it was an array I would just have to do array.map(item=>(<div>{item.name}</div>)) So having to reconsider this, is it worth to turn the array into an object or sticking with arrays?
No, not a good idea for a few reasons:
React relies on new references to objects (arrays, pojos, etc.) in order to know that a change has been made and that the DOM should update. Using delete on an object does not change its reference. Of course, you can be vigilant to avoid errors like these, but it's a most likely not a good idea because of reason 2.
Don't perform optimizations that make the code harder to reason about unless a performance problem has actually come up. The modern computer is extremely fast. You do not need to make the same performance considerations that programmers made 50 years ago. Does your array have tens of thousands of entries or thousands of entries, where entry in the array is an immensely complex object? If so, then I'd be happy to talk about various performance strategies.
If you have actually run into such severe issues, the solution is always context-dependent. What is slow about it? How much HTML are you rendering per entry in your Array#map operation? How often does the array need to be updated (aka state being triggered)? What is the most common array manipulation you end up using? How often are you updating the HTML?
Large HTML: Your real enemy is React's reconciliation algorithm/Virtual DOM. Pull out the HTML inside each map into a separate component. Design the component in a way where you can suppress propagating rerenders from the parent.
Virtualize (less HTML on the page) or paginate (smaller array to manipulate) your list. There's no silver bullet to avoid array manipulation. The best thing you can do is change the size of the array you are continually working with or change the amount of HTML that is getting rendered.
The slowest part of the browser is the DOM. Never forget that. In an overwhelming majority of situations, algorithms are chump change in comparison
I see your point, I've actually done the same a couple of times, but I'd say it depends on the case. In most cases, you'd rather keep the array.
Think about all of the higher-order array methods, each of them fulfills a specific purpose, like filter, find, some, or even the more complex ones like reduce. Usually, you'll manipulate a list of data quite a bit in frontend development
In Javascript objects(which are hash), this is the time complexity of the operations you want to perform:
Modification = O(1)
Deletion = Amortized O(1) meaning it will be constant for most
cases, but not necessarily all of them.
For arrays, since you are storing objects inside them as elements, you will have to filter them through traversal since you can't access them by index, which means your time complexity is:
Modification - O(n)
Deletion - O(n) may be O(n2) if you use splice for deletion
On the other hand:
array.map(item=>(<div>{item.name}</div>))
This will run a single loop so O(n)
As for this:
Object.keys(object).map(key=>(<div>{object[key].name}</div>))
This will be O(n2), one loop for Object.keys() and one for map(), which is still o(n)
So in conclusion, If you regularly need to modify, access or delete objects based on the id, stick with objects.
But for cases where you only need to render the list of objects or delete infrequently, stick with arrays.
Side note: Unless you frequently delete or modify these objects, stick with arrays. From a performance perspective, it is negligible if you only trigger these operations a few times.

JS Optimization/Performance: Comparing objects using JSON.stringify

I'm currently building a small application is Vanilla JS (without any dependencies like lodash/jquery) and I needed to compare two objects to check for equality in keys and values. I was just wondering about how to optimize this problem.
The keys of both objects are in the same order as they are derived from the same method. According to this answer, the fastest and most efficient way to do this is using JSON.stringify(object1) === JSON.stringify(object2).
However, in my app, if the two objects are not equal, then I loop through the two of them and perform some operations. The problem is that these operations are pretty performance heavy and run occasionally. I need to optimize my solution.
Therefore, I was wondering if JSON.stringify runs some sort of for loop internally as well. In my application, it is more likely for the two objects to be unequal. Therefore, if JSON.stringify also runs some sort of for loop, I could just remove the check and run the operations I need right away (which will only cause a difference in the program if the two objects are unequal) saving time and making it more optimized. If I don't do this, then I will technically be running two for loops for the exact same purpose when the two objects are unequal and running one for loop either way when the two objects are equal. If JSON.stringify is some sort of for loop internally, then I can just one for loop no matter if the objects are equal. Am I making sense here? Please let me know if you don't understand something. Is this check useless and should I remove it to optimize my code?
Your question touches 4 different areas:
The implementation (and thus performance) of JSON.stringify
The implementation (and thus performance) of object iteration
The quality and performance of the JIT compiler
The speed of memory allocation (JSON.stringify is a memory hog for big objects)
So it is quite clear, that there is now "Universal" answer for all JS engines and OSes.
I recommend you do checks your in code ... why?
While right now the order of attributes might be constant, future maintenance to your codebase might change that and introduce a hard to track down bug.
It is good practice to create an isEqual method for all object types you use
It is better readable.
Ofcourse there are also disadvantages:
Your code will become bigger (this might be linked to better readable)
ANything else I might have forgotten.

Why should I use immutablejs over object.freeze?

I have researched on net about the benefits of immutablejs over Object.freeze() but didn't find anything satisfying!
My question is why I should use this library and work with non native data structures when I can freeze a plain old javascript object?
I don't think you understood what immutablejs offers. It's not a library which just turns your objects immutable, it's a library around working with immutable values.
Without simply repeating their docs and mission statement, I'll state two things it provides:
Types. They implemented (immutable) infinite ranges, stacks, ordered sets, lists, ...
All of their types are implemented as Persistent Data Structures.
I lied, here's a quote of their mission statement:
Immutable data cannot be changed once created, leading to much simpler application development, no defensive copying, and enabling advanced memoization and change detection techniques with simple logic. Persistent data presents a mutative API which does not update the data in-place, but instead always yields new updated data.
I urge you to read the articles and videos they link to and more about Persistent Data Structures (since they're the thing immutablejs is about), but I'll summarise in a sentence or so:
Let's imagine you're writing a game and you have a player which sits on a 2d plane. Here, for instance, is Bob:
var player = {
name: 'Bob',
favouriteColor: 'moldy mustard',
x: 4,
y: 10
};
Since you drank the FP koolaid you want to freeze the player (brrr! hope Bob got a sweater):
var player = Object.freeze({
name: 'Bob',
...
});
And now enter your game loop. On every tick the player's position is changed. We can't just update the player object since it's frozen, so we copy it over:
function movePlayer(player, newX, newY) {
return Object.freeze(Object.assign({}, player, { x: newX, y: newY }));
}
That's fine and dandy, but notice how much useless copying we're making: On every tick, we create a new object, iterate over one of our objects and then assign some new values on top of them. On every tick, on every one of your objects. That's quite a mouthful.
Immutable wraps this up for you:
var player = Immutable.Map({
name: 'Bob',
...
});
function movePlayer(player, newX, newY) {
return player.set('x', newX).set('y', newY);
}
And through the ノ*✧゚ magic ✧゚*ヽ of persistent data structures they promise to do the least amount of operations possible.
There is also the difference of mindsets. When working with "a plain old [frozen] javascript object" the default actions on the part of everything is to assume mutability, and you have to work the extra mile to achieve meaningful immutability (that's to say immutability which acknowledges that state exists). That's part of the reason freeze exists: When you try to do otherwise, things panic. With Immutablejs immutability is, of course, the default assumption and it has a nice API on top of it.
That's not to say all's pink and rosy with cherry on top. Of course, everything has its downsides, and you shouldn't cram Immutable everywhere just because you can. Sometimes, just freezeing an object is Good Enough. Heck, most of the time that's more than enough. It's a useful library which has its niche, just don't get carried away with the hype.
According to my benchmarks, immutable.js is optimized for write operations, faster than Object.assign(), however, it is slower for read operations. So the descision depends the type of your application and its read/write ratio. Following are the summary of the benchmarks results:
-- 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).
Ideally, you should profile your application before introducing any performance optimization, however, immutability is one of those design decision must be decided early. When you start using immutable.js, you need to use it throughout your entire application to get the performance benefits, because interop with plain JS objects using fromJS() and toJS() is very costly.
PS: Just found out that deep freeze'ed array (1000 elements) become very slow to update, about 50 times slower, therefore you should only use deep freeze in development mode only. Benchmarks results:
-- Immutable (Object.assign) + deep freeze
Total elapsed = 45903 ms = 96 ms (read) + 45807 ms (write).
Both of them don't make the object deeply immutable.
However, using Object.freeze you'll have to create the new instances of the object / array by yourself, and they won't have structural sharing. So every change which will require deeply copying everything, and the old collection will be garbage collected.
immutablejs on the other hand will manage the collections, and when something changes, the new instance will use the parts of the old instance that haven't changed, so less copying and garbage collecting.
There are a couple of major differences between Object.freeze() and immutable.js.
Let's address the performance cost first. Object.freeze() is shallow. It will make the object immutable, but the nested properties and methods inside said object can still be mutated. The Object.freeze() documentation addresses this and even goes on to provide a "deepFreeze" function, which is even more costly in terms of performance. Immutable.js on the other hand will make the object as a whole (nested properties, method, etc) immutable at a lower cost.
Additionally should you ever need to clone an immutable variable Object.freeze() will force you to create an entirely new variable, while Immutable.js can reuse the existing immutable variable to create the clone more efficiently. Here's an interesting quote about this from this article:
"Immutable methods like .set() can be more efficient than cloning
because they let the new object reference data in the old object: only
the changed properties differ. This way you can save memory and
performance versus constantly deep-cloning everything."
In a nutshell, Immutable.js makes logical connections between the old and new immutable variables, thus improving the performance of cloning and the space frozen variables take in memory. Object.freeze() sadly does not - every time you clone a new variable from a frozen object you basically write all the data anew, and there is no logical connection between the two immutable variables even if (for some odd reason) they hold identical data.
So in terms of performance, especially if you constantly make use of immutable variables in your program, Immutable.js is a great choice. However, performance is not everything and there are some big caveats to using Immutable.js. Immutable.js uses it's own data structure, which makes debugging, or even just logging data to the console, a royal pain. It also might lead to a loss of basic JavaScript functionality (for example, you cannot use ES6 de-structuring with it) The Immutable.js documentation is infamously impossible to understand (because it was originally written for use only within Facebook itself), requiring a lot of web-searching even when simple issues arise.
I hope this covers the most important aspects of both approaches and helps you decide which will work best for you.
Object.freeze does not do any deep freezing natively, I believe that immutable.js does.
The same with any library -- why use underscore, jquery, etc etc.
People like re-using the wheels that other people built :-)
The biggest reason that comes to mind - outside of having a functional api that helps with immutable updates, is the structural sharing utilized by Immutable.js. If you have an application that needs enforced immutability (ie, you're using Redux) then if you're only using Object.freeze then you're going to be making a copy for every 'mutation'. This isn't really efficient over time, since this will lead to GC thrasing. With Immutable.js, you get structural sharing baked in (as opposed to having to implement an object pool/a structural sharing model of your own) since the data structures returned from immutable are Tries. This means that all mutations are still referenced within the data structure, so GC thrashing is kept to a minimum. More about this is on Immutable.js's docsite (and a great video going into more depth by the creator, Lee Byron):
https://facebook.github.io/immutable-js/

Can I increase lookup speed by positioning properties in object?

I've seen a lot of questions about the fastest way to access object properties (like using . vs []), but can't seem to find whether it's faster to retrieve object properties that are declared higher than others in object literal syntax.
I'm working with an object that could contain up to 40,000 properties, each of which is an Array of length 2. I'm using it as a lookup by value.
I know that maybe 5% of the properties will be the ones I need to retrieve most often. Is either of the following worth doing for increased performance (decreased lookup time)?
Set the most commonly needed properties at the top of the object literal syntax?
If #1 has no effect, should I create two separate objects, one with the most common 5% of properties, search that one first, then if the property isn't found there, then look through the object with all the less-common properties?
Or, is there a better way?
I did a js perf here: http://jsperf.com/object-lookup-perf
I basically injected 40000 props with random keys into an object, saved the "first" and "last" keys and looked them up in different tests. I was surprised by the result, because accessing the first was 35% slower than accessing the last entry.
Also, having an object of 5 or 40000 entries didn’t make any noticeable difference.
The test case can most likely be improved and I probably missed something, but there is a start for you.
Note: I only tested chrome
Yes, something like "indexOf" searches front to back, so placing common items higher in the list will return them faster. Most "basic" search algorithms are basic top down (simple sort) searches. At least for arrays.
If you have so many properties, they must be computed, no ? So you can replace the (string, most probably) computation by an integer hash computation, then use this hash in a regular array.
You might even use one single array by putting values in the 2*ith, 2*i+1th slot.
If you can use a typed array here, do it and you could no go faster.
Set the most commonly needed properties at the top of the object literal syntax?
No. Choose readability over performance. If you've got few enough properties that you use a literal in the code, it won't matter anyway; and you should order the properties in a logical sequence.
Property lookup in objects is usually based on hash maps, and position should not make a substantial difference. Depending on the implementation of the hash, they might be neglible slower, but I'd guess this is quite random and depends heavily on the applied optimisations. It should not matter.
If #1 has no effect, should I create two separate objects, one with the most common 5% of properties, search that one first, then if the property isn't found there, then look through the object with all the less-common properties?
Yes. If you've got really huge objects (with thousands of properties), this is a good idea. Depending on the used data structure, the size of the object might influence the lookup time, so if you've got a smaller object for the more frequent properties it should be faster. It's possible that different structures are chosen for the two objects, which could perform better than the single one - especially if you know beforehand in which object to look. However you will need to test this hypothesis with your actual data, and you should beware of premature [micro-]optimisation.

Categories

Resources