(Vue) 对计算属性中局部范围变量性能的影响

Posted

技术标签:

【中文标题】(Vue) 对计算属性中局部范围变量性能的影响【英文标题】:(Vue) Impact on performance of local scope variables in computed properties 【发布时间】:2019-02-17 08:16:24 【问题描述】:

在计算属性中定义变量对 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)的反应变量?

【问题讨论】:

【参考方案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);
&lt;script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"&gt;&lt;/script&gt;

【讨论】:

非常有趣,谢谢。我其实对这种行为的技术背景很感兴趣:Vue 的计算属性是根据它们的依赖关系缓存的,但乍一看这与局部变量无关。 一个可能导致加速的技术细节是 javascript 引擎可以 100% 确定该值永远不会改变,然后可以打开原本无法打开的优化。这就是为什么在您自己的应用程序中对其进行基准测试很重要的原因,因为这可能会在 javascript 优化器中采用不同的路径(在我的情况下,优化器可能已经做了 1 + 1 = 2 然后使用那个来计算总和计算更快) 我用字符串而不是整数重新创建了您的示例,并执行了过滤函数而不是对数字求和 - 结果是相同的。我最终会在 Vue 论坛上发布此内容,以获得进一步的技术见解。 实际上:使用循环是违反直觉的,因为循环会一次又一次地调用 Vue 的响应式 getter。在实际示例中,您只会调用一次 getter,因此此示例中巨大的性能差异没有意义(当然,只要您没有在计算属性中使用循环)。

以上是关于(Vue) 对计算属性中局部范围变量性能的影响的主要内容,如果未能解决你的问题,请参考以下文章

vue之watch和计算属性computed

什么是计算机的临时数据仓库,对计算机的系统性能影响很大

对vue中的computed属性,watch监听,计算属性理解

Vue 计算属性

python中函数的全局变量和局部变量

vue计算属性与watch监听