如何在不影响性能的情况下重复访问 Vue 道具? [英] How can I repeatedly access a Vue prop without tanking performance?

查看:20
本文介绍了如何在不影响性能的情况下重复访问 Vue 道具?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个存在性能问题的 Vue/Vuetify 应用程序.我创建了一个自定义组件,它环绕着 一个标准的 Vuetify v-data-table 组件.它适用于少量数据,但给它中到大量的数据会导致 Firefox 挂起和 Chrome 崩溃.

这是我的代码的稍微简化版本:

以下是 theValues 实际外观的示例:

<预><代码>[{数据: [[25389, 24890, 49021, ...] <-- 30,000 个元素],架构:[{col:id_number",类型:整数"}]}]

我看到的快速代码和慢速代码之间唯一有意义的区别是,慢速代码在每次迭代时访问 prop theValues 而快速代码不涉及 Vue 的任何复杂部分.(它确实使用了 theKeys,但即使我在函数内部创建 theKeys 的本地深层副本,性能也不会改变.)

基于此,问题似乎不是数据表组件无法处理我发送的数据量,或者嵌套循环本质上效率太低.我最好的猜测是,从 prop 中读取这么多内容会以某种方式减慢 Vue 本身的速度,但我并不能 100% 确定这一点.

但我最终确实需要将道具中的信息放入表格中.我该怎么做才能以合理的速度加载?

解决方案

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

for (i...) {对于 (j...) {theValues[0].data[i][j]//平均约 50 毫秒(昂贵)}}//=>32K 物品的长挂

优化是在循环外缓存数组,这会显着缩短循环执行时间并解决挂起问题:

const myData = theValues[0].data为我...) {对于 (j...) {myData[i][j]//~0.00145 ms 平均值}}//=>约 39 毫秒(32K 项)

演示 1

请注意,使用 JavaScript API 可以在没有循环的情况下计算相同的结果.这以轻微的性能成本(~1ms)提供了可读性和减少的代码行数.具体来说,使用 Array.prototype.mapdata 中的每个值映射到一个对象属性,通过 Array.prototype.reducetheKeys 上:

theValues[0].data.map(values => theKeys.reduce((obj,key,i) => {对象[键] = 值[i]返回对象}, {}))//=>约 40 毫秒(32K 项)

演示 2

以上时间在 2016 年 MacBook Pro 上测得 - 2.7GHz i7、Chrome 87.Codesandbox 演示可能会显示与上面的巨大差异.

I'm working on a Vue/Vuetify app that has a performance problem. I've created a custom component that wraps around a standard Vuetify v-data-table component. It works fine for small amounts of data, but giving it moderate to large amounts of data causes Firefox to hang and Chrome to crash.

Here's a slightly simplified version of my code:

<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>

And here's an example of what theValues actually looks like:

[
  {
    data: [
            [25389, 24890, 49021, ...] <-- 30,000 elements
          ],
    schema: [
              {
                col: "id_number",
                type: "integer"
              }
            ]
  }
]

The only meaningful difference I see between the fast code and the slow code is that the slow code accesses the prop theValues on each iteration whereas the fast code doesn't touch any complicated part of Vue. (It does use theKeys, but the performance doesn't change even if I create a local deep copy of theKeys inside the function.)

Based on this, it seems like the problem is not that the data table component can't handle the amount of data I'm sending, or that the nested loops are inherently too inefficient. My best guess is that reading from the prop so much is somehow slowing Vue itself down, but I'm not 100% sure of that.

But I do ultimately need to get the information from the prop into the table. What can I do to make this load at a reasonable speed?

解决方案

The performance problem is actually a symptom of your loop code rather than Vue. The most expensive data access is in your inner loop in dataForDataTable():

for (i...) {
  for (j...) {
    theValues[0].data[i][j]  // ~50 ms average (expensive)
  }
}

// => long hang for 32K items

An optimization would be to cache the array outside your loop, which dramatically improves the loop execution time and resolves the hang:

const myData = theValues[0].data

for (i...) {
  for (j...) {
    myData[i][j]  // ~0.00145 ms average
  }
}

// => ~39 ms for 32K items

demo 1

Note the same result can be computed without loops, using JavaScript APIs. This affords readability and reduced lines of code at a slight performance cost (~1ms). Specifically, use Array.prototype.map to map each value from data to an object property, obtained by Array.prototype.reduce on theKeys:

theValues[0].data
  .map(values => theKeys.reduce((obj,key,i) => {
    obj[key] = values[i]
    return obj
  }, {}))

// => ~40 ms for 32K items

demo 2

Times above measured on 2016 MacBook Pro - 2.7GHz i7, Chrome 87. Codesandbox demos might show a vast variance from the above.

这篇关于如何在不影响性能的情况下重复访问 Vue 道具?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆