【问题标题】:Improving performance for many Vue components on the same page提高同一页面上许多 Vue 组件的性能
【发布时间】:2019-03-08 04:30:16
【问题描述】:

我正在构建一个在同一个视图中安装数百甚至数千个 vue 组件实例的应用程序。每个组件都有一个 id,它引用 vuex 存储中的一个对象。

<my-component :id="item1"></my-component>
<my-component :id="item2"></my-component>
<my-component :id="item3"></my-component>
...

商店:

state: {
  myComponentData: [
    {
      id: 'item1',
      name: 'Hawaiian Shirt', 
      selected: false,
      // ...
    },
    // ...
  ]
}

my-component 中,我在 store 中查找它的对象并将其存储在计算属性中:

computed: {
  myComponentData: function () {
    return this.$store.state.myComponentData.find(el => el.id === this.id);
  },
  isSelected: function () {
    return this.myComponentData.selected;
  },
  // ...
}

可以通过与组件本身或应用程序中其他位置的其他组件交互来操作商店中的对象属性。

问题是当我尝试使用数百或 1000 多个元素运行此程序时,加载需要 30 秒或更长时间。

如果我删除计算的属性,或者用静态值替换它们,那么页面会无缝加载。只有当我尝试从存储中加载所有计算属性时才会出现延迟问题。

在加载许多(1500 多个)使用计算属性和 Vuex 的 Vue 组件时,有没有办法提高性能?我已经研究了动态/异步组件、vue-async-computed 和 vue-rx 作为可能的解决方案,但我不确定在这种情况下哪个会有所帮助。

【问题讨论】:

  • 我认为您最好的选择是在处理大型列表时采用虚拟滚动包之类的方法。本质上,不要渲染组件,直到它在 DOM 中可见(或在某个 +/- 阈值内)。
  • 除了@DigitalDrifter 所说的,您也可以使用功能组件。 vuejs.org/v2/guide/render-function.html#Functional-Components

标签: asynchronous vue.js vuex


【解决方案1】:

我认为Array.find() 操作成本最高。将它放在计算属性中意味着每次依赖项更改时它都会运行。

您可以在mounted() 中获取数组索引并在计算中使用它,

export default {
  name: "MyComponent",
  props: ["id"],
  data() {
    return {
      storeIndex: -2
    };
  },
  mounted() {
    this.storeIndex = this.$store.state.myComponentData.findIndex(
      el => el.id == "item" + this.id
    );
  },
  computed: {
    myComponentData: function() {
      // return this.$store.state.myComponentData.find(
      //   el => el.id === "item" + this.id
      // );
      return this.$store.state.myComponentData[this.storeIndex] || {};
    },
    isSelected: function() {
      return this.myComponentData.selected;
    }
  }
};

这是一个CodeSandbox 的工作示例。

【讨论】:

  • 你是对的。 Array.find() 操作似乎正在执行此操作。我今天尝试了这种方法,但findIndex() 仍然非常昂贵,即使它只被处理一次。我想我会尝试重构我的代码并使用下面的解决方案来完全取消计算。
  • 如果一个组件的数据可以被另一个更改,我认为你需要一个计算或一个 getter 来让它们反应。为了取消findIndex,我将专注于如何实例化存储数据和组件。
  • 好主意,但我认为它可能会破坏逻辑 - 如果您删除一个项目怎么办?索引不再相同,然后您就有了这个巨大的更新?
  • 没有足够的信息来确定删除,但我想说的是有一个属性来指示“已删除”,然后在组件模板中使用v-show 实现。
  • 更笼统地说,避免改变数组。
【解决方案2】:

问题出在逻辑上。如果您有 1000 个项目,则创建 1000 个组件。然后他们每个人都循环遍历项目列表,以便根据 id 找到合适的项目。所以你基本上是在做 1000 * 1000 循环(当然是最坏的情况)。这不是最糟糕的事情 - 您正在通过这个计算属性添加反应性!每次发生变化时,计算方法都会再次触发,导致另一个 1000 循环(如果您的项目是最后一个,则最坏的情况是)。

你有几个选择:

  1. 在您的组件中设置数据时获取商店的商品。这不会创建计算属性,因此您将拥有静态数据。这将导致为您想要更改的所有数据创建自己的个人观察者。

  2. (我会同意)您在显示列表的父组件中拥有项目列表。不要只传递 id - 传递整个项目。这样您就不需要使用任何计算属性,并且您将拥有开箱即用的反应性(props 会在子项中自动更新)。

只是不要添加那么多循环和计算属性 - 顾名思义,它们是用于计算,而不是用于过滤可以在其他地方过滤的东西;)

祝你好运!

【讨论】:

  • #2 将需要一些代码重构,但我认为这是要走的路。谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-08-01
  • 2021-03-16
  • 1970-01-01
  • 1970-01-01
  • 2019-08-05
  • 2015-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多