10

私はさまざまな情報源から、mobx がレンダラーに反応し、redux よりも高速であることを読みました。しかし、いくつかのテストを行ったところ、mobx オブザーバブルへの新しいデータの追加がかなり遅いことがわかりました。反応ネイティブ環境では、ミリ秒ごとにカウントされ、200 要素をループして配列を埋めるのに 100 ミリ秒以上かかるソリューションを使用するのは難しいです私は本当に mobx を楽しんでいるので、誰かがテスト コードを見て、いくつかのヒントを与えてくれることを願っています - 私が間違っていることと、パフォーマンスを改善する方法。

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();

私のラップトップでは、完了するまでに約120ミリ秒かかります。observable-s がなければ、1 ミリ秒もかかりません

4

5 に答える 5

30

基本的に間違っていることは何もありません (ただし、Robert が既に示したように、現在、すべてのプロパティがとにかく監視可能になっています。これは、デフォルトでプレーン データ構造を再帰的に監視できるためです)。

主なことは、まだMobXを実際に使用していないということです:)テスト結果は正しく、観察可能なデータ構造はプレーンな構造よりもはるかに高価です。りんごとみかんを少し比べてみました。または、より良いアナロジーのために。これは、文字列を連結して HTML を生成するベンチマークと、DOM を使用して HTML を生成するベンチマークのようなものです。弦は必ず勝つ。

ただし、完全なアプリの全体像では、状況は異なります。要素の境界線の色を変更する必要があるとします。そうすると、DOM は、HTML の非常に特定の部分のみを変更できるようになり、DOM は画面上で再描画する必要があるピクセルを正確に判断できるほどスマートになるため、おそらく突然、はるかに効率的になります。むき出しの弦だけだと、それはずっと難しくなります。

MobX も同様で、高速なデータ構造からパフォーマンスを得るのではなく、そのスマートさから得られます。監視可能な配列が変更された場合、MobX は、記述した計算と一貫性を保つために、どのアクション、どのコンポーネントをレンダリングする必要があるかを正確に特定します。MobX は、その種のものを手動で記述する場合よりもはるかにきめ細かい「イベント リスナー」を確立できるため、また MobX は依存関係ツリーを最適化できるため、人間のプログラマーがおそらく気にしないことですが、MobX は非常に便利です。速い。ただし、状態の完全なライフサイクルの全体像でそれを見る必要があります。いくつかのオブジェクトと配列を非常に高速に作成したいだけなら、単純な配列とコンストラクター関数に勝るものはありません。

@lavrton https://medium.com/@lavrton/how-to-optimise-rendering-of-a-set-of-elements-in-react-ad01f5b161ae#.enlk3n68gによるこのブログを読むことをお勧めします。これは、MobX がコンポーネントを更新できる速度に近づけるために、手動で最適化するときにジャンプする必要があるすべてのフープをうまく示しています。

それがあなたの結果を説明することを願っています!

PS 現在、大規模なコレクションをソートまたはクリーンアップするときに MobX が遅くなることが知られているケースがいくつかあります。ただし、これらは次の 2.4.0 リリースで対処される予定です。

于 2016-07-19T19:30:53.847 に答える
10

observable()配列にプッシュするすべての値を (再帰的に) 観測可能にしますが、これは必要なものではない場合があります。

たとえば、コード例から、idおよびaプロパティの変更のみを監視し、残りの変更を監視したくない場合があります。その場合、監視可能な配列でasFlat修飾子を使用できます。

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

これにより、listそれ自体 (新しい項目の追加、削除された項目など) への変更、またはリスト項目のidおよびaプロパティへの変更を観察できますが、残りは観察できません。

これにより、テストが大幅に高速化されます。35ms から約 5ms です。

于 2016-07-19T17:47:07.230 に答える
3

そうしないと、パフォーマンスpushreplace何倍も速くなります。

ライブラリを評価し、数千またはレコードを (制限を押し上げるために) 試した場合、負荷によってブラウザーがフリーズしました。に変更しましreplaceたが、ミリ秒の問題でした。

于 2018-02-21T20:48:41.447 に答える
1

あなたのコードをフィドルで試してみましたが、結果は 35ms でした。しかし、通常、for()ループは他の代替手段よりも高価です。ここでは、Array.map()1000 の例を使用したより高速なコードを示します。私のマシンでは、約 59 ミリ秒で実行されます (平均を取得するために何度も試行します)。

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();

jsフィドル

ただし、コンポーネントの更新に関して Mobx オブザーバブルのパフォーマンスについて公正な結論を得るために、Redux を使用して React の実際のケースを比較する必要があります。

于 2016-07-19T15:46:34.873 に答える
0

すべての新しいアイテムをトランザクションの外で作成した場合のパフォーマンスはどうですか?

const start = new Date().getTime();
const newItems = [];
for (let i = 0; i < 200; i++) {
    newItems.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',

    });
}
transaction(() => {
    Array.prototype.push.apply(this.items, newItems)
});

次に、observablearoundidおよびなしoneで試してから、トランザクションなしで試します ( へのすべての変更が...this.itemsへの 1 回の呼び出しで行われるため)Array.prototype.push

于 2016-07-19T14:46:46.797 に答える