10

我从不同的来源了解到 mobx 的性能优于 react 渲染器,并且比 redux 更快。但是,如果我进行了几次测试,它表明向 mobx 可观察对象添加新数据非常慢。在 react-native 环境中,每毫秒都很重要,使用解决方案很棘手,即使循环超过 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 需要不到 1ms

4

5 回答 5

30

你没有做任何根本性的错误(除了,正如罗伯特已经指出的那样,目前所有属性都是可观察的,因为默认情况下可观察到在普通数据结构上递归)。

主要的是你还没有真正使用 MobX :) 你的测试结果是正确的,可观察的数据结构比普通结构要贵得多。这有点比较苹果和橙子。或者为了更好的类比;这就像对连接字符串进行基准测试以生成 HTML 与使用 DOM 生成 HTML。弦乐总会赢。

然而,在一个完整的应用程序的大局中,事情是不同的。假设您需要更改元素的边框颜色。然后 DOM 可能会突然变得更有效率,因为它只允许您改变 HTML 的非常特定的部分,并且 DOM 足够聪明,可以准确地决定哪些像素需要在屏幕上重新绘制。如果你只有一根裸线,这一切都会变得更加困难。

MobX 类似,它的性能不是来自快速的数据结构,而是来自它们的智能。如果一个 observable 数组被修改,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()使您在数组中(递归地)推送的所有值都可以观察到,这可能不是您需要的。

例如,根据您的示例代码,您可能只想观察ida属性的变化,而不是其余的。在这种情况下,您可以在可观察数组上使用asFlat修饰符:

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

这将允许您观察list自身的变化(添加的新项目、删除的项目等)或列表项目的ida属性,但不能观察其余部分。

这对我来说大大加快了您的测试速度:从 35 毫秒到大约 5 毫秒。

于 2016-07-19T17:47:07.230 回答
3

不这样做pushreplace您会看到性能快很多倍。

在评估库并尝试数千条记录(以推动限制)时,负载会冻结浏览器。我将其更改replace为几毫秒。

于 2018-02-21T20:48:41.447 回答
1

我在小提琴中尝试了你的代码,结果是 35 毫秒。但通常,for()循环比其他替代方案更昂贵,这是一个使用 1000 个示例的更快代码Array.map(),在我的机器中执行时间约为 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();

jsFiddle

但是,您应该比较使用 Redux 的 React 真实案例,以便在更新组件时获得关于 Mobx 可观察对象性能的公平结论。

于 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)
});

然后尝试不使用observablearound idand one,然后尝试不使用事务(因为所有更改this.items现在都在一次调用中完成Array.prototype.push...)

于 2016-07-19T14:46:46.797 回答