Search code examples
performancevue.jsvuejs2computed-properties

(Vue) Impact on performance of local scope variables in computed properties


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?


Solution

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