⬆️ ⬇️

The future of javascript MVC frameworks

Introducing Om







We, in our ClojureScript corner, have long known this — all of our data structures are immutable and based on original Clojure collections written in Java. Modern JavaScript engines are currently quite optimized and we often see the performance of these collections within 0.4X from the JVM.



Stop, stop, stop. And what about the performance of immutable data structures to JavaScript MVC? - Quite substantial.

')

Perhaps it will not be very easy to explain, but still I will try. The fact is that the immutable data structures presented in the new Om library allow you to create applications an order of magnitude more efficiently than on popular JS MVC frameworks such as MVC Backbone.js (without manual optimization). Om is built on a beautiful Facebook framework - React . If you have not heard of it before, I recommend watching videos from JSConf EU 2013. An interesting fact is that due to its unchangeable collections, Om can show better results than when using React without any modifications.



The benchmarks that are presented later were not created to prove that Om is the fastest library in the world for building a UI. They were created to demonstrate that decisions are often made that cannot be globally optimized. Also, modern frameworks often provide a small amount of documentation and assistance, and therefore users make decisions that lead to performance problems.



Of course, problems in applications can be tediously solved one by one. But you can use frameworks like Om, which provide complex levels of abstraction of components. This will help get rid of a number of simple and time-consuming manual optimization methods.



Benchmark Game



Open Om TodoMVC in a browser and run the first benchmark. It creates 200 list items, and on 11 inch Macbook Air in Safari 7, it runs in 120ms.



Now open Backbone.js TodoMVC and run a similar benchmark. On my machine, the page rendered in about 500ms.



In Chrome and Firefox, on my machine, Om shows results about 2-4 times faster than Backbone.js.

If you try to switch all the items in the list, Om will do it instantly, whereas with a similar action Backbone.js will show a slight freeze.

This difference is probably due to the fact that Om redraws the page during the requestAnimationFrame event. This allows you to significantly optimize your application.



Let's take a look at the profiler in Chrome Dev Tools for these benchmarks. We can see a big difference in the work of React / Om out of the box compared to the non-optimized Backbone.js:



React / Om:





Backbone.js:





In my opinion, the React / Om graph shows that there are much more opportunities for global optimizations and improvements.



Good, great job! But still ... Only the fact of increasing productivity in 3 main browsers by 2-4 times should already have interested many. Especially considering that we reach this level thanks to immutable data structures. There is no increase in 30-40 times, which was made by me on Twitter.



Now try the second Om benchmark - it creates 200 elements, switches them all 5 times, and then deletes them. In Safari 7 on my MacBook, this all happens in about 5ms.



Next, run Backbone.js. Make sure you delete all the items first, and then try the second benchmark. On my machine in the Safari browser, it ran for 4200ms.



How is this possible? - Simply.



Om almost never performs unnecessary work. Data, views, and controller logic are unrelated. When changing data, we will never immediately render the page. We simply postpone the redrawing of changes until the requestAnimationFrame event. In fact, Om works with the browser as a GPU.



I assume that many JS MVC applications replicate the Backbone.js TodoMVC application architecture, linking together model and view changes, as well as other independent parts, such as serializing the state of the application in LocalStorage. Only a few frameworks provide the necessary support to properly build the architecture of their applications. In fact, this is not surprising, since most frameworks are based on string templates, CSS selectors, and direct manipulation of the DOM. Om leaves behind all signs of a place-oriented programming style and other potential performance vulnerabilities.



Of course, you can use Backbone.js or your favorite JS MVC framework with React, and this is a good combination that provides great benefits . However, I do not believe in event-oriented MVC systems. And the benchmarks above confirm this. Separation of models and representations is only the first important step.



I hope this will give reasons for reflection to fans of current JS MVC frameworks, and even to people who believe in using only native JavaScript and jQuery. Above, I tried to show that JavaScript-compiled language, which uses slower data structures, is ultimately faster than its competitor to build more complex interfaces. At the top of the best results list is Om TodoMVC with the same functionality as all other frameworks, with a volume of ~ 260 lines of code (including all template) and a reduced weight of 63K gzipped (this all includes: React - 27K, standard ClojureScript library, core.async, routing library, and several Google helpers Closure).



If you're a JavaScript developer, I think you should take a good look at React. I think in the future, connecting React with a library that enables the use of persistent data structures, such as mori , can lead JavaScript applications to the flexible and very well-configured architecture that Om provides. Despite the fact that immutable data structures generate more garbage, we still hope that modern developers will cope with this problem. Also, the performance of the devices we carry in our pockets is constantly improving.



Technical description follows.



How it works



Changes and queries to the DOM tree are a big performance vulnerability, and React uses an approach that bypasses these places by sacrificing expressiveness. It provides a well-designed object-oriented interface, but if you look under the hood, we will see the source code, which was created from the point of view of the pragmatic functional programmer. It generates virtual versions of the DOM tree, and as soon as changes occur in your application, Om marks the changes between the virtual versions of the DOM tree at intervals. It is used to get the minimum amount of change that is needed for a real DOM tree.



In React, there is a rather important function called shouldComponentUpdate, which is used when calculating the difference in the virtual DOM represented by your components. If it returns false, then React will never evaluate the children of this component. Thus, React gradually builds a virtual DOM tree to get data about the elements that need to be changed.



As it turned out, the default implementation of shouldComponentUpdate is too conservative, because JavaScript developers tend to modify objects and arrays. Therefore, to determine the properties of the component that have changed, you must manually pass through the objects and arrays.



Instead of using JavaScript objects, Om uses data structures from ClojureScript, which, as we know, cannot be changed. Based on this, we can provide a component that implements shouldComponentUpdate, by using the fastest check for equality of links. This means that we can always determine what has changed in structure during logarithmic time.



Therefore, we do not require operations like setState, which are used to support efficient updates of tree nodes, as well as a good object-oriented style. Updating tree nodes in Om, starting from the top point always happens faster, because we only compare the links on the way down.

Also, because we always redraw from the top of the tree, the combined updates are trivial to implement. We do not worry about the support of combined updates with React, as it is designed to handle these cases for us.



And finally, since we always have the initial state of the UI for each piece of data, you can simply serialize all the important application states. You no longer have to worry about the serialization protocol, since the Om UI states are always serializable.



It also means that Om UI returns a status instantly. You can easily save any state in memory and can return to it whenever you want. This is an efficient use of memory, since ClojureScript data structures are implemented using memory sharing for them.



Final thoughts



In conclusion, I do not think that the current generation of JavaScript MVC frameworks has many prospects in the future. I think that if you sit and think about it, you will get something like React / Om. This can provide the optimal balance between simplicity, performance and expressiveness. There is nothing that was not known before ... If you begin to perceive the browser as a means of remote page rendering and stop storing any garbage there, then everything will work much faster. Sounds like something familiar, right? Yes, like computer graphics programming.

Source: https://habr.com/ru/post/208978/



All Articles