(Vue) Влияние на производительность переменных локальной области видимости в вычисляемых свойствах

Влияет ли определение переменных внутри вычисляемого свойства на производительность компонентов Vue?

Справочная информация: я создал компонент таблицы, который генерирует таблицу HTML в целом из переданных данных и имеет разные фильтры для каждого столбца, фильтр для всей таблицы, ключи сортировки и т. д., поэтому я определяю много локальных переменных внутри вычисляемого свойства.

Представьте, что у вас есть массив объектов:

let data = [
  { id: "y", a: 1, b: 2, c: 3 },
  { id: "z", a: 11, b: 22, c: 33 }
]

..который используется компонентом Vue для отображения данных:

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

Данные фильтруются через ввод:

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

Мой вопрос относится к let data = .. и let filterKey = .., поскольку filteredData() запускается при любом изменении filterKey (определенного в data()), поэтому локальная переменная тоже обновляется, хотя они не реагируют на Vue.

Есть ли какое-либо влияние на производительность при определении локальных переменных внутри вычисляемого свойства? Следует ли использовать реактивные переменные из data() (например, this.filterKey) непосредственно внутри вычисляемого свойства?


person Bennett Dams    schedule 12.09.2018    source источник


Ответы (1)


Лучший способ проверить, влияет ли что-то на производительность, - это проверить это.

Согласно моим тестам, приведенным ниже, использование this.passedData вместо добавления переменной поверх функции более чем на 1000% медленнее. (869 мс против 29 мс)

Для достижения наилучших результатов убедитесь, что вы запускаете тесты в целевых браузерах, в которых пишете приложение.

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>

person Ferrybig    schedule 12.09.2018
comment
Очень интересно, спасибо. На самом деле меня интересует техническая подоплека этого поведения: вычисляемые свойства Vue кэшируются на основе их зависимостей, но на первый взгляд это не имеет ничего общего с локальными переменными. - person Bennett Dams; 12.09.2018
comment
Одна техническая деталь, которая может вызвать ускорение, заключается в том, что механизм javascript может быть на 100% уверен, что значение никогда не изменится, и затем может включить оптимизацию, которую в противном случае он не сможет включить. Вот почему так важно протестировать его в своем собственном приложении, так как это может идти по другому маршруту в оптимизаторе javascript (в моем случае оптимизатор уже может сделать 1 + 1 = 2, а затем использовать его для вычисления суммы расчет быстрее) - person Ferrybig; 12.09.2018
comment
Я воссоздал ваш пример со строками вместо целых чисел и выполнил функцию фильтрации вместо суммирования чисел - результат тот же. В конце концов я опубликую это на форуме Vue, чтобы получить дополнительную техническую информацию. - person Bennett Dams; 12.09.2018
comment
На самом деле: использование циклов противоречит здравому смыслу, поскольку цикл снова и снова вызывает геттер реактивности Vue. В реальном примере вы вызываете метод получения только один раз, поэтому огромные различия в производительности в этом примере не имеют смысла (если, конечно, вы не используете цикл в вычисляемом свойстве). - person Bennett Dams; 25.10.2018