When changes are too expensive: JavaScript and data change performance.
Tags: webdev, javascript, programming, opensource
Published: 2023-10-02 02:35:27

Approaches to data processing and manipulation remain one of the key aspects of software development.
_Immunability_, _reactivity_, and _mutability_ are key strategies in data state management, and choosing between them can significantly affect application performance.,

In JavaScript, the importance of choosing an approach to data processing is closely related to the features of this language and the scope of its application. JavaScript is primarily used to develop the client side of web applications, where performance is a key factor. The user experience directly depends on how quickly and efficiently the application processes and displays data.

Immunability in JavaScript can be quite expensive. Every time the state changes, a new object is created, which leads to increased memory usage and load on the garbage collector. In a language with dynamic typing and automatic memory management, such operations can affect performance significantly more than, for example, in languages with static typing and manual memory management.

In front-end JavaScript, the problem of immunability is getting worse. The user interface often requires a lot of state updates, which in the case of immutability can lead to the creation of a large number of objects and, accordingly, to an increased load on the processor and memory. Such resource costs in the context of a browser, where available resources are usually limited, can lead to lower performance and a worse user experience.

Nevertheless, despite its _"cost"_, immutability continues to be popular in the JavaScript world. One example is the **Redux** state management library, where immunability is used to ensure predictability and simplify tracking of state changes. Immunability can facilitate the development process by providing clear and unambiguous rules for changing the state, which can be very valuable in complex applications with a large number of interdependencies.

And what about the mutable approach? For example - **MobX**. This library is regarded by many as an analogue of Redux, but from the camp of a mutable approach. However, you can often hear that Redux has more performance than **MobX**, which contradicts what we talked about. After all, in a mutable approach, we simply change the value in memory.

For example, I wrote 2 versions of a simple **React** application. One using **Redux**, the other with **MobX**. In all other respects, they are completely identical. The application is a background counter that is updated 1 time per second. A button that changes color by hover. And a simulation of sending N files to the server. When sending information changes, it should be updated in the interface. Sending occurs asynchronously and starts at different times for everyone, with random file size. This application lacks a complex interface and so on, but it demonstrates well the user's need to use the application while something is being done in the background (I will provide access to each application at the end of the article).

Here is the result when sending **50** files.

![upload 50 files with redux](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxo962e5pw7m6u4d3ztr.gif)

![upload 50 files with mobx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o2phieobr20sq1lo92wi.gif)

There are no differences in performance here. The main counter changes 1 time per second. The color change and text highlighting are triggered. Updating information is not lagging.



When sending **100** files, the lags are already noticeable.

![upload 100 files with redux](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/seq1b53q2keu9utokc9v.gif)

![upload 100 files with mobx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivw3qmuzd327e247vfo4.gif)

When sending **500** files, the application can no longer be used and it makes no sense to test with a larger number of files.

![upload 500 files with redux](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pk6qnjjtv9cracsto0w0.gif)

![upload 500 files with mobx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v5er3odnn3l26lj2lbf7.gif)

If you look to measure the execution time of the update function, it turns out that **Redux** is really faster than **MobX**. But with the increase in the number of files, this difference is greatly reduced.

It turns out that mutability is no faster than immunability? What is the point of realizing that an application with **MobX** works faster than the same application with **Redux**, if both of them cannot be used?
In fact, **MobX** has tried to combine reactivity and mutability and performs too many calculations for this. In **MobX**, a state change can cause side effects in other parts of the application through mechanisms such as observables and reactions. This means that when a state changes (mutates), all parts of the system that depend on this state automatically react to these changes. In addition, the `observer` function imposes additional costs and in console or server JavaScript - **MobX** will be more productive than in the frontend. 

Then how to make it better? How to make sure that our application does not lag, and we can send 500 files without harm?

Let's take into account the development environment, in our case, **JavaScript**. _Many argue for immutability, and they have valid points. However, it is foolish to disregard the impact it has on performance in JavaScript. Therefore, it may not be the optimal solution to the problem._ 
And the problem is a **safe state** with a **clear data flow**. 
**Mutability** - does not guarantee that some value in the code will be accidentally redefined, etc. And it's true. But JavaScript is a language that actively uses mutability within itself. It turns out there is a way to track changes in entities. This method is a `Proxy`. `Proxy` is used to define user behaviors on objects and allows you to create various types of traps for objects. But **MobX** uses a `Proxy`! Yes, but with reservations. Let's just say `Proxy` is used there more for other things than for state control.
Libraries for state management are often regarded as a place where you need to shove all the business logic. From this, the vector of the library's purpose shifts from the original one - state management.

Before proceeding to the details of what should be taken into account in the state management library in the first place, let's look at another example of an application we know, but with a different library. **Statemanjs**. 

**50** files.

![upload 50 files with statemanjs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hnjh8fzvnkq7u9jonnm.gif)

**100** files.

![upload 100 files with statemanjs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11idexpj4m2rpsu5avtg.gif)

**500** files.

![upload 500 files with statemanjs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4mgrdwu2vr63psvwn6po.gif)

Even **1000** files without lags.

![upload 1000 files with statemanjs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/19ad22csbcf8cs4g3tz9.gif)

And only when sending **5000** files there are lags, and then because of React. Nevertheless, even with lags, the application can still be used, unlike Redux and **MobX** when sending **500** files.

![upload 5000 files with statemanjs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y9bvxd2kgy83l8ot3lor.gif)

Is this some kind of lite version of **MobX**? So it's even less secure and functional?
This is not a lite version of MobX and _with MobX, statemanjs - binds only `Proxy`_. But `Proxy` is used here in a radically different way. More native to the language itself. Providing monitoring and security of the condition. 
**Statemanjs** uses the concept of references for reading, and you can change the state only with built-in methods. This makes it predictable, secure and, as we have seen, faster. 
I will not talk in detail about **statemanjs**. You can read the official documentation - [Link](https://github.com/persevie/statemanjs), there are also benchmarks and comparison with other state management libraries. In this article, I wanted to draw your attention to how important it is to understand the design of the development environment. Data structures and data modification methods. 

Thank you all and have a good coding!

---

[redux codesanbox](https://codesandbox.io/s/redux-gj6965)
[mobx codesanbox](https://codesandbox.io/s/mobx-lghz2s)
[statemanjs codesanbox](https://codesandbox.io/s/statemanjs-xzh3g7)