Does defining variables inside of a computed property have any impact on the perfomance of Vue components?
Background: I built a table component which generates a HTML table generically from the passed data and has different filters per column, filter for the whole table, sort keys, etc., so I'm defining a lot of local variables inside the computed property.
Imagine having an array of objects:
let data = [
{ id: "y", a: 1, b: 2, c: 3 },
{ id: "z", a: 11, b: 22, c: 33 }
]
..which is used by a Vue component to display the data:
<template>
<div>
<input type="text" v-model="filterKey" />
</div>
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody>
<tr v-for="item in filteredData" :key="item.id">
<td v-for="(value, key) in item" :key="key">
{{ value }}
</td>
</tr>
</tbody>
</table>
</template>
The data gets filtered via input:
<script>
export default {
props: {
passedData: Array,
},
data() {
return {
filterKey: null,
};
},
computed: {
filteredData() {
// defining local scope variables
let data = this.passedData;
let filterKey = this.filterKey;
data = data.filter((e) => {
// filter by filterKey or this.filterKey
});
return data;
},
},
};
</script>
My question refers to let data = ..
and let filterKey = ..
as filteredData()
gets triggered from any change of the filterKey
(defined in data()
) so the local variable gets updated too, although they're not "reactive" in a Vue way.
Is there any impact on the performance when defining local variables inside a computed property? Should you use the reactive variables from data()
(e. g. this.filterKey
) directly inside of the computed property?
The best way to test if something affects performance, is to actually test it.
According to my tests below, it is consistency more than 1000% slower to use this.passedData
instead of adding a variable on top of the function. (869ms vs 29ms)
Make sure you run your benchmarks on the target browsers you write your application for the best results.
function time(name, cb) {
var t0 = performance.now();
const res = cb();
if(res !== 20000000) {
throw new Error('wrong result: ' + res);
}
var t1 = performance.now();
document.write("Call to "+name+" took " + (t1 - t0) + " milliseconds.<br>")
}
function withoutLocalVar() {
const vue = new Vue({
computed: {
hi() {
return 1;
},
hi2() {
return 1;
},
test() {
let sum = 0;
for(let i = 0; i < 10000000; i++) { // 10 000 000
sum += this.hi + this.hi2;
}
return sum;
},
}
})
return vue.test;
}
function withLocalVar() {
const vue = new Vue({
computed: {
hi() {
return 1;
},
hi2() {
return 1;
},
test() {
let sum = 0;
const hi = this.hi;
const hi2 = this.hi2;
for(let i = 0; i < 10000000; i++) { // 10 000 000
sum += hi + hi2;
}
return sum;
},
}
})
return vue.test;
}
function benchmark() {
const vue = new Vue({
computed: {
hi() {
return 1;
},
hi2() {
return 1;
},
test() {
let sum = 0;
const hi = 1;
const hi2 = 1;
for(let i = 0; i < 10000000; i++) { // 10 000 000
sum += hi + hi2;
}
return sum;
},
}
})
return vue.test;
}
time('withoutLocalVar - init', withoutLocalVar);
time('withLocalVar - init', withLocalVar);
time('benchmark - init', benchmark);
time('withoutLocalVar - run1', withoutLocalVar);
time('withLocalVar - run1', withLocalVar);
time('benchmark - run1', benchmark);
time('withoutLocalVar - run2', withoutLocalVar);
time('withLocalVar - run2', withLocalVar);
time('benchmark - run2', benchmark);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>