简体   繁体   English

Vue v-for性能很差

[英]Vue v-for performance is poor

I have about 4000 objects being returned via AJAX. 我有大约4000个对象通过AJAX返回。 I'm looping over them with v-for and spitting them out into a table. 我用v-for循环它们并将它们吐出到表中。

The initial load and render is very fast but I've also got an input field I'm using for 'instant search'. 初始加载和渲染非常快,但我也有一个输入字段,我用于'即时搜索'。 I use a computed property to filter the dataset using the input value and on a small dataset, say up to about 100 results this works superbly but as the dataset gets larger it gets a lot slower. 我使用一个计算属性来使用输入值和一个小数据集来过滤数据集,比如最多大约100个结果,这可以很好地工作,但随着数据集变大,它会慢得多。

I'm rendering a table with 4 values, one of which is a custom Component. 我正在渲染一个包含4个值的表,其中一个是自定义组件。 Removing the Component speeds things up but I'm surprised that it's this bad a performance hit. 删除组件可以加快速度,但我很惊讶这是一个糟糕的性能影响。 I'm not sure if there's something I'm missing or if someone could point me in the right direction? 我不确定是否有什么东西我不知道或者有人能指出我正确的方向吗?

I know its a large amount of data for one page but I thought this was what Vue was supposed to be good at. 我知道它有一个页面的大量数据,但我认为这是Vue应该擅长的。 I googled the issue and for instance I found this codepen rendering a similar list of items and filtering in exactly the same way and I could copy-paste the number of items in the array all the way up to 10,000 or so and there was no perceptible performance hit when searching. 我搜索了这个问题,例如我发现这个codepen呈现了一个类似的项目列表,并以完全相同的方式进行过滤,我可以将数组中的项目数量一直复制粘贴到10,000左右,并且没有可察觉的搜索时性能受到影响。

Steps I've taken to speed things up, these have made either tiny or no improvements: 我采取的步骤是为了加快速度,这些步骤已经做了很小的改进或没有改进:

  • Added a v-bind:key with a unique value on the v-for 在v-for上添加了一个v-bind:key,其唯一值
  • Not using the table element and instead using div or ul 不使用table元素而是使用div或ul
  • Forgoing the nativeJS .filter method because it can be slow, and using my own filter method. 放弃nativeJS .filter方法,因为它可能很慢,并使用我自己的过滤方法。
  • Trying running it on a fresh codebase with only the dependencies that are needed to run. 尝试在新代码库上运行它,只需要运行所需的依赖项。
  • And I am aware of pagination techniques etc. but I'm unwilling to do that unless I've exhausted all other possibilities. 而且我知道分页技术等,但我不愿意这样做,除非我已经用尽所有其他可能性。

Thanks 谢谢

It wants me to paste code here, even though I've linked to codepen so here's the JS without the items array. 它希望我在这里粘贴代码,即使我已经链接到codepen所以这里的JS没有items数组。

    Vue.component('my-component', {
  template: '#generic-picker',
  props:['items','query','selected'],
  created: function(){
    this.query='';
    this.selected='';
  },
  computed:{
    filteredItems: function () {
      var query = this.query;
      return this.items.filter(function (item) {
        return item.toLowerCase().indexOf(query.toLowerCase()) !== -1})
    }
  },
  methods:{
    select:function(selection){
      this.selected = selection;
    }
  }
})
// create a root instance
var genericpicker = new Vue({
  el: '#example'
});

The problem with using a computed array is that things have to be un-rendered and re-rendered as if you're using v-if , when you're in a situation where v-show is a better choice. 使用计算数组的问题在于,当你处于v-show是更好的选择的情况时,事物必须被解除渲染并重新渲染,就好像你正在使用v-if

Instead, keep an indicator for each item for whether it should be displayed, and use v-show based on that. 相反,请为每个项目保留一个指示符,以确定是否应该显示该项目,并根据该项目使用v-show The snippet below implements both, selectable by checkbox. 下面的代码段实现了两个,可通过复选框选择。 You will find that filter updates are a bit halting when not using the v-show version, but keep up quite well when using v-show . 你会发现,当不使用v-show版本时,过滤器更新有点暂停,但在使用v-show时保持良好状态。

Most noticeable when you filter it down to 0 rows (say, filter on x) then show everything (remove the filter), but you can see a difference in partial filtering like me 2 当你将它过滤到0行时最明显(比如,在x上过滤)然后显示所有内容(删除过滤器),但你可以看到像me 2这样的部分过滤的区别me 2

 let arr = []; for (let i=0; i<6000; ++i) { arr.push({name: `Name ${i}`, thingy: `Thingy ${i}`}); } Vue.component('tableRow', { template: '<tr><td>{{name}}</td><td>{{thingy}}</td></tr>', props: ['name', 'thingy'] } ); new Vue({ el: '#app', data: { arr, filter: 'x', useVshow: false }, computed: { filteredArr() { return this.filter ? this.arr.filter((item) => item.name.indexOf(this.filter) > -1) : this.arr; } }, watch: { filter() { for (const i of this.arr) { i.show = this.filter ? i.name.indexOf(this.filter) > -1 : true; } } } }); 
 <script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script> <div id="app"> Filter: <input v-model="filter"> Use v-show: <input type="checkbox" v-model="useVshow"> <table> <tr> <th>Name</th> <th>Thingy</th> </tr> <template v-if="useVshow"> <tr is="tableRow" v-for="row in arr" v-show="row.show" :key="row.name" :name="row.name" :thingy="row.thingy"></tr> </template> <template v-else> <tr is="tableRow" v-for="row in filteredArr" v-show="row.show" :key="row.name" :name="row.name" :thingy="row.thingy"></tr> </template> </table> </div> 

If you're not interested in two-way and/or reactive binding, that is, if you only want to visualize the objects rather than being able to edit them or update the view when the data changes, you can speed up performance dramatically with Object.freeze . 如果您对双向和/或反应绑定不感兴趣,也就是说,如果您只想显示对象而不是能够在数据更改时编辑它们或更新视图,则可以显着提高性能Object.freeze This way, Vue.js can't add watchers on every property and instead only read the properties. 这样,Vue.js就无法在每个属性上添加观察者,而只是读取属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM