Javascript 我如何在没有坦克性能的情况下重复访问Vue道具?
我正在开发一个有性能问题的Vue/Vuetify应用程序。我已经创建了一个环绕的自定义组件。它可以很好地处理少量数据,但是给它中到大量的数据会导致Firefox挂起,Chrome崩溃 下面是我的代码的一个稍微简化的版本: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()
<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
虽然Vuecomputed
属性经过高度优化,但每次访问属性时仍有一些代码在运行(检查底层数据是否脏,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"
}
]
}
]