Javascript 我如何在没有坦克性能的情况下重复访问Vue道具?

Javascript 我如何在没有坦克性能的情况下重复访问Vue道具?,javascript,performance,vue.js,vuetify.js,Javascript,Performance,Vue.js,Vuetify.js,我正在开发一个有性能问题的Vue/Vuetify应用程序。我已经创建了一个环绕的自定义组件。它可以很好地处理少量数据,但是给它中到大量的数据会导致Firefox挂起,Chrome崩溃 下面是我的代码的一个稍微简化的版本: <script> import ... export default { props: { theValues: Array, // other props }, computed: { theKeys: function()

我正在开发一个有性能问题的Vue/Vuetify应用程序。我已经创建了一个环绕的自定义组件。它可以很好地处理少量数据,但是给它中到大量的数据会导致Firefox挂起,Chrome崩溃

下面是我的代码的一个稍微简化的版本:

<script>
import ...

export default {
  props: {
    theValues: Array,
    // other props
  },

  computed: {
    theKeys: function() {
      return this.schema.map(col => col.col);
    },

    schema: function() {
      return this.theValues[0].schema;
    },

    dataForDataTable: function() {
      console.time('test');

      let result = [];
      for (let i = 0; i < theValues[0].data.length; i++) {
        let resultObj = {};
        for (let j = 0; j < theKeys.length; j++) {
          // The "real" logic; this causes the browser to hang/crash
          // resultObj[theKeys[j]] = theValues[0].data[i][j];

          // Test operation to diagnose the problem
          resultObj[theKeys[j]] = Math.floor(Math.random() * Math.floor(99999));
        }
        result.push(resultObj);
      }

      console.timeEnd('test');
      // For ~30k rows, timer reports that:
      // Real values can take over 250,000 ms
      // Randomly generated fake values take only 7 ms

      return result;
    },

    // other computed
  },

  // other Vue stuff
</script>
我看到的快速代码和慢速代码之间唯一有意义的区别是,在每次迭代中,慢速代码访问prop
值,而快速代码不涉及Vue的任何复杂部分。(它确实使用了
按键
,但即使我在函数中创建了
按键
的本地深度副本,性能也不会改变。)

基于此,问题似乎不是数据表组件无法处理我发送的数据量,或者嵌套循环本身效率太低。我最好的猜测是,从道具上读这么多东西会让Vue的速度减慢,但我不是100%确定

但我最终需要从道具中获取信息。如何使此负载以合理的速度运行?

提示1 原文:

访问道具(
数据
)不应成为问题。是的,
数据
是被动的,但读取它应该非常有效(Vue只是“记下”您正在使用该数据进行渲染)

看来我显然错了

您的组件正在通过prop获取数据,但数据很可能在父组件中是被动的(来自Vuex或存储在父组件的
数据中)。Vue 2反应性系统的问题在于它所基于的,并且该系统不允许拦截索引阵列访问(Vue无法将类似
arr[1]
的代码检测为模板依赖项)。为了解决这个问题,如果访问了对象属性(
代码中的值[0]。数据),它将检查该值是否为数组,如果是,它将迭代整个数组(加上所有嵌套数组)-您可以阅读更深入的解释

这个问题的一个解决方案是创建局部变量
let data=theValues[0]。数据
,如tony19所示。现在不是每次都调用
.data
Vue getter,而且性能是固定的

但如果您的数据是不可变的(从不更改),只需使用
Object.freeze()
,Vue将不会尝试检测此类数据的更改。这不仅可以加快代码的速度,还可以在对象列表较大的情况下节省时间

注意这个问题在Vue 3中得到了解决,因为它使用了基于ES6代理的非常不同的反应性系统

提示2 虽然Vue
computed
属性经过高度优化,但每次访问属性时仍有一些代码在运行(检查底层数据是否脏,computed prop是否需要重新评估),如果您像您的案例那样在一个紧密的循环中使用它,那么这项工作将累加起来。。。 在执行循环之前,尝试对键进行本地拷贝(浅拷贝就足够了,不需要深拷贝)

从Vue核心成员处可以看到这一点


当然,同样的问题也适用于从模板访问
dataForDataTable
computed prop。我鼓励您尝试使用watcher而不是
computed
来实现与
dataForDataTable
相同的逻辑,并将其结果存储在
data
中,以查看它是否有任何区别…

性能问题实际上是循环代码的症状,而不是Vue。最昂贵的数据访问在
dataForDataTable()中的内部循环中:

用于(i…){
对于(j…){
值[0]。数据[i][j]/~50毫秒平均值(昂贵)
}
}
//=>32K项的长挂
一种优化方法是在循环外部缓存阵列,这可以显著提高循环执行时间并解决挂起问题:

const myData=值[0]。数据
为了(我…){
对于(j…){
myData[i][j]/~0.00145毫秒平均值
}
}
//=>~39毫秒,用于32K个项目

注意:使用JavaScript API,可以不使用循环计算相同的结果。这提供了可读性并减少了代码行数,但性能成本很低(~1ms)。具体地说,用于将
数据中的每个值映射到对象属性,该属性通过键
获得:

theValues[0]。数据
.map(值=>theKeys.reduce((obj,key,i)=>{
obj[key]=值[i]
返回obj
}, {}))
//=>~40毫秒,用于32K个项目


在2016年MacBook Pro上测得的上述次数-2.7GHz i7,Chrome 87。Codesandbox演示可能与上述内容存在很大差异。

我想知道这是否与访问道具有关。你能试着拉出循环不变的部分吗?在循环之前,
const thePropData=theValues[0]
,然后在循环中
propdata[i][j]
。这有区别吗?(哦,还有迭代检查
i
)为什么需要迭代
数组?为什么不使用vuejs提供的反应性呢?我已经尝试过类似的方法,将调用从内部循环中拉出,而不是从外部循环中拉出。这没有什么区别,事后看来,这是因为在简化的示例中只有一列。把它再往上拉一层,脱离外环,成功了。发帖作为回答?@Danizavtz抱歉,我不明白你的建议是什么?可以确认在内部循环中直接访问
值[0]
会降低性能,但在循环外分配它是黄金。不支持减少,但这是个人偏好。看到这个答案我真的很惊讶。简单数组访问(
值[0]。数据
)怎么会这么慢??但你们似乎是对的,这与Vue的反应性有关——你们可以通过离开原始版本得到几乎相同的结果<
[
  {
    data: [
            [25389, 24890, 49021, ...] <-- 30,000 elements
          ],
    schema: [
              {
                col: "id_number",
                type: "integer"
              }
            ]
  }
]