浅谈Vue 性能优化之深挖数组(6)

ob _.dep 当中去,这样只要内部发生变化,就能通过 dep 获取到 renderWatcher,通知它更新。

那么结合我的业务代码,就分析出来问题出现在语句3当中。

<div class="card-content">
 <div class="block" v-for="item in cardData" :key="item.secName">
  <div class="sub-title">{{item.secName}}</div>
  <div class="group">
   <span
    @click="cardClick(index + item.startIndex)"
    class="item"
    :class="getItemClass(index + item.startIndex)"
    v-for="(subItem, index) in item.secTids"
    :key="subItem">{{index + item.startIndex + 1}}</span>
  </div>
 </div>
</div>
getItemClass (index) {
 const ret = {}
 // 如果是做对的题目,但并不是当前选中
 ret['item_true'] = this.questions[index]......
 // 如果是做对的题目,并且是当前选中
 ret['item_true_active'] = this.questions[index]......
 // 如果是做错的题目,但并不是当前选中
 ret['item_false'] = this.questions[index]......
 // 如果是做错的题目,并且是当前选中
 ret['item_false_active'] = this.questions[index]......
 // 如果是未做的题目,但不是当前选中
 ret['item_undo'] = this.questions[index]......
 // 如果是未做的题目,并且是当前选中
 ret['item_undo_active'] = this.questions[index]......
 return ret
},

首先 cardData 是一个分组数据,循环里面套循环,假设有 10 个章节, 每个章节有 200 道题目,那么其实会执行 2000 次 getItemClass 函数,getItemClass 内部会有 6 次对 questions 进行求值,每次都会走到 dependArray,每次执行 dependArray 都会循环 2000 次,所以粗略估计 2000 * 6 * 2000 = 2400 万次,如果假设一次执行的语句是 4 条,那么也会执行接近一亿次的语句,性能自然是原地爆炸!

既然从源头分析出了原因,那么就要找出方法从源头上去解决。

拆分组件

很多人理解拆分组件是为了复用,当然作用不止是这些,拆分组件更多的是为了可维护性,可以更语义化,在同事看到你的组件名的时候,大概能猜出里面的功能。而我这里拆分组件,是为了隔离无关的响应式数据造成的组件渲染。从上图可以看出,只要任何一个响应式数据改变,Paper 都会重新渲染,比如我点击收藏按钮,Paper 组件会重新渲染,按道理只要收藏按钮这个 DOM 重新渲染即可。

在嵌套循环中,不要用函数

性能出现问题的原因是在于我用了 getItemClass 去计算每一个小圆圈的样式,而且在函数里面还对 questions 进行了求值,这样时间复杂度从 O(n²) 变成了 O(n³)(由于源码的 dependArray也会循环)。最后的解决方案,我是弃用了 getItemClass 这个函数,直接更改了 cardData 的 tids 的数据结构,变成了 tInfo,也就是在构造数据的时候,计算好样式。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/123.html