最近的某次代码评审中,某位同事对我的代码提出了一个优化点:for循环中不要去用this.xxx这样的语句,要用局部变量保存该属性,如:
for (let i = 0; i < this.tableData.length; i++) {
const row = this.tableData[i];
row.date = this.currentData;
}
// 应优化为
const tableData = this.tableData
const currentData = this.currentData
for (let i = 0; i < tableData.length; i++) {
const row = tableData[i];
row.date = currentData;
}
这个优化原理很简单,局部变量的访问速度比属性快,用局部变量去缓存属性自然能在循环中获得效率提升。
参与代码评审的领导听了觉得这种优化可以作为一种标准,每个for循环都这么处理,但是我提出异议,表示这样的优化不值得去做,因为只有数据量达到上万条可能才会有一点点效果,但领导觉得以后可能会碰上这种情况,还是坚持这个优化标准,我虽然还想反驳,但是一时也没想到太充分的理由。
所以会后我就开始思考,这种优化方式的优缺点,首先,实践出真知,我先写个简单的demo来看下这种优化提升的效率:
<div id="app"></div>
<script src="https://lib.baomitu.com/vue/2.6.14/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
currentData: new Date(),
tableData: []
},
created() {
console.time('time') // 开始时间
for (let i = 0; i < 1000; i++) {
this.tableData.push({
name: 'name',
date: this.currentData
})
}
console.timeEnd('time') // 结束时间
// 优化后
console.time('time2') // 开始时间
const tableData = this.tableData
const currentData = this.currentData
for (let i = 0; i < 1000; i++) {
tableData.push({
name: 'name',
date: currentData
})
}
console.timeEnd('time2') // 结束时间
},
template: `<div>{{tableData.length}}</div>`
})
</script>
页面运行起来后,在控制台现实的代码执行时间分别为:
也就是说,这种优化在上面的例子中做到了一千条数据提升了0.24ms的优化速度。再试试一万和十万条数据:
提升2.2ms。
提升55.1ms。
虽然这个例子比较简单,实际情况可能会更明显一点,但其实也是能看出,只有大量数据情况下,这种优化才有比较显著的效果,而在平常的业务开发中,这种大量数据是比较少见的。一般循环可能撑死了也就几百次,人根本感觉不出性能的提升,只有开发者孤芳自赏:哥的代码写的真是好!
这种优化的缺点是什么呢?就是代码的冗余!如果你的for循环里面调用了10个不同的属性,那么你将要多写10行代码,增加了工作量和降低了可读性,仅仅是为了优化一点微不足道的性能。
当然,如果一个for循环调用了多次相同的属性,我认为是可以用局部变量缓存起来的,因为这样做实际上即精简了代码,又提升了性能,一举两得。
以上的例子只是针对普通的前端业务开发,如果是在写框架或者工具,那么这种优化方式是没问题的,因为底层的工具总是需要尽可能地优化性能。
总结
前端代码优化是需要考虑成本和收益的,大家不要在某些文章里面看到一些优化方案,就生搬硬套把它用起来,而是要结合实际场景去考虑。
在我的工作经验中,前端业务开发最大的痛点不是性能,而是增强代码的可维护性、可读性和健壮性,应该把主要的精力放在这些方面,而不是在低效的优化中消耗自己有限的精力,陷入自我内卷的漩涡之中。