Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mobx performance

I read from different sources that mobx outperforms react renderer and are faster then redux. However if I made couple of tests it shows that adding new data to mobx observables are pretty slow. In react-native environment every milliseconds counts and it's tricky to use solution where even looping over 200 elements and filling array takes more then 100ms As I really enjoy mobx I hope someone can take a look a test code and give me some hints - what I'm doing wrong and how to improve performance.

import {observable, transaction,autorun} from 'mobx'; 
class Runner {

list = observable([]);

run() {


    const start = new Date().getTime();
    transaction(() => {
        for (let i = 0; i < 200; i++) {
            this.list.push({
                id: observable(i),
                one: observable('1'),
                two: '2',
                three: 3,
                x: 'xxxxx',
                y: 'yyyyy',
                z: 'zzzzz',
                z1: 'zzzzz',
                z2: 'zzzzz',
                z3: 'zzzzz',
                z4: 'zzzzz',

            });
        }
    });

    console.log('Execution time: ' + (new Date().getTime() - start) + 'ms services ');
}
}
const runner = new Runner();
autorun(() => console.log(runner.list));
runner.run();

On my laptop it's takes about 120ms to complete. Without observable-s it's takes less then 1ms

like image 472
Mac Avatar asked Jul 19 '16 13:07

Mac


4 Answers

You are doing nothing fundamentally wrong (except, that, as Robert already indicated, currently all properties are made observable anyway, because observable by default recurses on plain data structures).

The main thing is that you aren't really using MobX yet :) Your tests results are correct, observable data structures are a lot more expensive then plain structures. It's a little bit comparing apples with oranges. Or for a better analogy; It is like benchmarking concatening strings to produce HTML versus using the DOM to generate HTML. The strings will always win.

However, in the bigger picture of a complete app, things are different. Suppose that you need to change the border color of an element. Then the DOM will probably suddenly be a lot more efficient, as it allows you to only mutate a very specific piece of your HTML, and the DOM is smart enough to decide precisely which pixels needs to be repainted on the screen. That would all be a lot harder if you had just a bare string.

MobX is similar, doesn't get it's performance from fast data structures, but from their smartness. If an observable array is modified, MobX pinpoints precisely which actions, which components need to be rendered to be consistent with any computation you write. Because MobX is able to establish far more fine grained 'event listeners' then you would do when writing that kind of stuff by hand, and because MobX can optimize dependency trees, what a human programmer probably won't bother doing, MobX can be very fast. But you have to see it in the bigger picture of the complete lifecycle of your state. If you just want to create some objects and arrays very fast, nothing will beat plain arrays and constructor functions.

I recommend to read this blog by @lavrton https://medium.com/@lavrton/how-to-optimise-rendering-of-a-set-of-elements-in-react-ad01f5b161ae#.enlk3n68g. It nicely demonstrates all the hoops you need to jump trough when optimizing manually, just to get close to the speed at which MobX can update components.

I hope that explains your results!

P.S. there are currently a few known cases where MobX can be slow when sorting or cleaning up large collection. Those will be addressed by the upcoming 2.4.0 release though.

like image 140
mweststrate Avatar answered Oct 16 '22 08:10

mweststrate


Don't push but replace and you will see the performance many times faster.

When evaluating the library and tried thousands or records (to push the limits) the load would freeze the browser. I changed it to replace and it was a matter of milliseconds.

like image 41
s1mpl3 Avatar answered Oct 16 '22 07:10

s1mpl3


observable() makes all values that you push in the array (recursively) observable, which may not be what you need.

For instance, from your example code it may follow that you only want to observe changes to the id and a properties, not to the rest. In which case, you can use the asFlat modifier on your observable array:

const { observable, autorun, transaction, asFlat } = mobx;
....
list = observable(asFlat([]));

This will allow you to observe changes to list itself (new items added, items removed, etc), or to the id and a properties of the list items, but not the rest.

This speeds up your test considerably for me: from 35ms to about 5ms.

like image 10
robertklep Avatar answered Oct 16 '22 07:10

robertklep


I tried your code in a fiddle, the result was 35ms. But usually, for() loops, are more expensive than other alternatives, here is a more faster code using Array.map() with 1000 examples, in my machine performs at ~59ms(try many times to get average):

const { observable, autorun, transaction } = mobx;

class Runner {

  @observable list = [];

  run() {
    const start = new Date().getTime();
    transaction(() => {
     this.list = new Array(1000).fill(0).map((row, i) => {
        return {
          id: observable(i),
          a: observable('1'),
          two: '2',
          three: 3,
          x: 'xxxxx',
          y: 'yyyyy',
          z: 'zzzzz',
          z1: 'zzzzz',
          z2: 'zzzzz',
          z3: 'zzzzz',
          z4: 'zzzzz',
        };
      });
    });
    console.log('Execution time: ' + (new Date().getTime() - start) + 'ms services ');
    console.log('list observable->', this.list);
  }
}
const runner = new Runner();
autorun(() => console.log(runner.list));
runner.run();

jsFiddle

However you should compare a React real case using Redux in order to get a fair conclusion about Mobx observables perfomance when it comes to updating components.

like image 1
agualbbus Avatar answered Oct 16 '22 08:10

agualbbus