You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
在node下,由上面的数据可以很明显的看出,forEach、map和for of 这些ES6+的语法并没有传统的for循环或者while循环快,特别是map方法。但是由于map有返回值,无需额外调用新数组的push方法,所以在执行浅拷贝任务上,内存占用很低。而for of语法在内存占用上也有一定的优势。顺便提一下:for循环 while循环 for of 循环是可以通过break关键字跳出的,而forEach map这种循环是无法跳出的。
前言
前端开发中经常涉及到数组的相关操作:去重、过滤、求和、数据二次处理等等。都需要我们对数组进行循环。为了满足各种需求,JS除了提供最简单的
for
循环,在ES6
和后续版本中也新增的诸如:map、filter、some、reduce
等实用的方法。因为各个方法作用不同,简单的对所有涉及到循环的方法进行执行速度比较,是不公平的,也是毫无意义的。那么我们就针对最单纯的以取值为目的的循环进行一次性能和效率测试,用肉眼可见的方式,对JS中常见的这些数组循环方式进行一次探讨。从最简单的for循环说起
for
循环常见的四种写法,不啰嗦,直接上代码第一种方法是最常见的方式,不解释。
第二种方法是将
persons.length
缓存到变量len
中,这样每次循环时就不会再读取数组的长度。第三种方式是将取值与判断合并,通过不停的枚举每一项来循环,直到枚举到空值则循环结束。执行顺序是:
i = 0
和变量person
i
项persons[i]
赋值给变量person
并判断是否为Truthyperson
i++
。第四种方法是倒序循环。执行的顺序是:
i
i
是否大于0并执行i--
persons[i]
,此时的i
已经-1
了四种
for
循环方式在数组浅拷贝中的性能和速度测试先造一个足够长的数组作为要拷贝的目标(如果
i
值过大,到亿级左右,可能会抛出JS堆栈跟踪的报错)然后分别用四种循环方式,把数组中的每一项取出,并添加到一个空数组中,也就是一次数组的浅拷贝。并通过console.time和console.timeEnd记录每种循环方式的整体执行时间。通过process.memoryUsage()比对执行前后内存中已用到的堆的差值。
分别调用上述方法,每个方法重复执行12次,去除一个最大值和一个最小值,求平均值(四舍五入),最终每个方法执行时间的结果如下表(测试机器:
MacBook Pro (15-inch, 2017) 处理器:2.8 GHz Intel Core i7 内存:16 GB 2133 MHz LPDDR3
执行环境:node v10.8.0
):node
下执行完成同一个数组的浅拷贝任务,耗时方面四种方法的差距微乎其微,有时候排序甚至略有波动。v8引擎
新版本针对对象取值等操作进行了最大限度的性能优化,所以方法二中缓存数组的长度到变量len
中,并不会有太明显的提升。即使是百万级的数据,四种for循环
的耗时差距也只是毫秒级,内存占用上四种for循环方式也都非常接近。在此感谢YaHuiLiang、七秒先生、戈寻谋doxP、超级大柱子的帮助和指正,如果大佬们有更好的见解也欢迎评论留言。同样是
v8引擎
的谷歌浏览器
,测试发现四种方法也都非常接近。但是在
火狐浏览器
中的测试结果:方法二 ≈ 方法三 ≈ 方法四 < 方法一,表明二三四这三种写法都可以在一定程度上优化for循环
而在
safari浏览器下
:方法四 < 方法一 ≈ 方法二 ≈ 方法三,只有方法四体现出了小幅度的优化效果。小结
考虑到在不同环境或浏览器下的性能和效率:
推荐
:第四种i--
倒序循环的方式。在奇舞团的这篇文章——嗨,送你一张Web性能优化地图的2.3 流程控制
小节里也略有提及这种方式。不推荐
:第三种方式。主要是因为当数组里存在非Truthy
的值时,比如0
和''
,会导致循环直接结束。while
循环以及ES6+的新语法forEach
、map
和for of
,会更快吗?不啰嗦,实践是检验真理的唯一标准
测试方法同上,测试结果:
在
node
下,由上面的数据可以很明显的看出,forEach
、map
和for of
这些ES6+
的语法并没有传统的for
循环或者while
循环快,特别是map
方法。但是由于map
有返回值,无需额外调用新数组的push
方法,所以在执行浅拷贝任务上,内存占用很低。而for of
语法在内存占用上也有一定的优势。顺便提一下:for循环 while循环 for of 循环
是可以通过break
关键字跳出的,而forEach map
这种循环是无法跳出的。但是随着执行环境和浏览器的不同,这些语法在执行速度上也会出现偏差甚至反转的情况,直接看图:
谷歌浏览器
火狐浏览器
safari浏览器下
可以看出:
ES6+
的循环语法会普遍比传统的循环语法慢,但是火狐和safari中情况却几乎相反。map
特殊,速度明显比其他几种语法慢,而在火狐和safari中却出现了反转,map
反而比较快!总结
之前有听到过诸如“缓存数组长度可以提高循环效率”或者“ES6的循环语法更高效”的说法。说者无心,听者有意,事实究竟如何,实践出真知。抛开业务场景和使用便利性,单纯谈性能和效率是没有意义的。 ES6新增的诸多数组的方法确实极大的方便了前端开发,使得以往复杂或者冗长的代码,可以变得易读而且精炼,而好的
for
循环写法,在大数据量的情况下,确实也有着更好的兼容和多环境运行表现。当然本文的讨论也只是基于观察的一种总结,并没有深入底层。而随着浏览器的更新,这些方法的孰优孰劣也可能成为玄学。目前发现在Chrome Canary 70.0.3513.0
下for of
会明显比Chrome 68.0.3440.84
快。如果你有更深入的见解或者文章,也不妨在评论区分享,小弟的这篇文章也权当抛砖引玉。如果你对数组的其他循环方法的性能和效率也感兴趣,不妨自己动手试一试,也欢迎评论交流。The text was updated successfully, but these errors were encountered: