开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
循环效率大乱斗
本文是以诙谐解说的方式来对比循环的效率。
本次的参赛选手
今天!是个好日子,我们吃着火锅,唱个歌,迎来了第x界循环效率大乱斗比赛。
好!话不到多说,现在有请我们的参赛选手依次入场。
for
第一位向我们走来的选手是循环届最负盛名的for循环,这位选手想必大家都非常熟悉,它以灵活多变闻名,相信很多人第一个循环都使用这位选手完成的,也是本次比赛的夺冠热门。
forEach
第二位入场的选手也是一位流量大咖,它就是forEach循环,它以简洁著称,这位选手虽然是for的晚辈,但是现如今的流量可能已经不输前辈了,不知道它能取得什么名次呢。
for in
不知不觉间第三位选手已经昂首挺胸迈入赛场了,它就是for in,相较于前两位选手,这位名气可能稍弱,但它有一项本领是前两位不具备,那就是遍历对象,想必其他本领也不会弱。
for of
紧随其后的第四位选手,是长得有点像第三位选手的for of,这位选手和第三位选手长得像名气也相当,只是它们的内在大相径庭,它只能遍历类对象,但是不知道速度方面和第三位比怎么样呢。
while
最后一位进场的也是我们非常熟悉的一位老前辈while循环,虽然它平时露面的机会比for循环少,但是它的实力不容小视。
比赛事项
本次比赛项目为遍历数组Array,看谁消耗的时间最短,那么就胜出。
本次比赛场地有两个分别为浏览器环境和node环境。
鉴于本次参加比赛的都是实力不俗的选手,因此就不墨迹了,直接给各位强者上难度。
本次的数组长度分别为10w、100w、1000w、10000w。
每种数组长度测试10次,最后取平均值平均值,数组长度越长得到的名次在最后综合排列名次中占比更重。
比赛开始 - Chrome浏览器
话不多说,直接开始比赛:
let arr = new Array(1000000).fill(0)
// 循环的内容
function contentFn(val) {
let arr1 = []
arr1.push(val)
}
// 第一位选手
function forFn() {
console.time('for');
for (let i = 0; i < arr.length; i++) {
contentFn(i)
}
console.timeEnd('for')
}
forFn()
// 第二位选手
function forEachFn() {
console.time('forEach');
arr.forEach(el => {
contentFn(el)
})
console.timeEnd('forEach')
}
forEachFn()
// 第四位选手
function forOfFn() {
console.time('for of');
for (let el of arr) {
contentFn(el)
}
console.timeEnd('for of')
}
forOfFn()
// 第五位选手
function whileFn() {
console.time('while');
let i = 0
while(i < arr.length) {
i++
contentFn(i)
}
console.timeEnd('while')
}
whileFn()
// 第三位选手
function forInFn() {
console.time('for in');
for (let el in arr) {
contentFn(el)
}
console.timeEnd('for in')
}
forInFn()
复制代码
执行10w得到得结果看图
执行100w得到得结果看图
执行1000w得到得结果看图
执行10000w得到得结果看图
好!接下来就是公布各位选手在个个阶段10次比赛的平均成绩,让我们看看哪位选手斩获这本场比赛的归桂冠
| 10w | 100w | 1000w | 10000w | |
|---|---|---|---|---|
| for | 7.1822ms | 25.2873ms | 175.0104ms | 1,862.1599ms |
| forEach | 4.2489ms | 22.8398ms | 216.1508ms | 2,236.4897ms |
| for of | 4.0124ms | 24.5814ms | 220.6332ms | 2,313.8196ms |
| for in | 16.8878ms | 170.3812ms | 3,035.8804ms | - |
| while | 2.8484ms | 18.9055ms | 163.6673ms | 1,750.6513ms |
最终成绩
第五名: for in
for in循环在遍历得数组的所有场次比赛中,只能说很拉来形容,成绩远远落后于其他选手,以至于最后一场它放弃了(其实是我怕浏览器和我电脑顶不住),毫无悬念取得了最后一名的成绩。
第四名: for of
for of循环在几次比赛中表现虽然不错但是有点后程乏力,名次不断下降,几场比赛分别取得2、3、4、4的成绩,因此综合下来排名第四名。
第三名: forEach
forEach循环在几次的比赛中名次都比较稳定,几场比赛分别取得3、2、3、3的名次,因为最后3次比赛中表现得比for of要好些,因此综合排名第三名
第二名: for
夺冠热门for循环在一开始的10w、100w的比赛中表现并不亮眼,都是只拿到了倒数第二的成绩,但是随着数组长度越长,表现越来越好,在后面的比赛中都取得很不错的成绩,而且相对三四名有较为明显的优势,因此综合来看将它排在第二名
第一名: while
while循环在几场比赛中都取得了非常好的成绩,均是第一名,而且优势十分明显,因此毫无悬念的取得了第一名的佳绩。
比赛开始 - node环境-版本v16.14.2
由于代码是一样的代码只是执行环境不一样了,因此就不贴代码了,直接上每次循环比赛的结果图
执行10w得到得结果看图
执行100w得到得结果看图
执行1000w得到得结果看图
执行9000w得到得结果看图
我的电脑中node环境只要超过9000w那么执行得就很慢,所以选择9000w来测试。
好!接下来就是公布各位选手在node环境个个阶段10次比赛的平均成绩,让我们看看哪位选手斩获这本场比赛的归桂冠
| 10w | 100w | 1000w | 9000w | |
|---|---|---|---|---|
| for | 7.3959ms | 28.7827ms | 203.7933ms | 3.0794s |
| forEach | 3.737ms | 28.7672ms | 241.6281ms | 3.3221s |
| for of | 5.4965ms | 32.982ms | 256.4202ms | 3.8941s |
| for in | 20.378ms | 243.8211ms | 2.2438s | - |
| while | 4.2982ms | 24.8978ms | 189.8527ms | 3.038s |
最终成绩
在node环境中计时只要超过1000ms的就会转换成1s,因此上表有些事s单位
第五名: for in
for in循环在node环境中遍历数组的成绩还是和浏览器中的一样,每次都处于垫底,因此还是一样倒数第一名。
第四名: for of
for of循环在node环境中的成绩也和浏览器一样,分别是3、4、4、4,因此也还是处于第四名
第三名: forEach
forEach循环在node环境中,在10w场次时拿到了第一的名次,但是后面的名次就开始下滑,因此综合来看还是处于第三名。
第二名: for
for循环前面两回合依旧发挥不佳,但是后来居上,有越战越勇的趋势,因此综合位于第二名。
第一名: while
while循环在node环境中没有在浏览器中这么强势了,在10w的比赛中屈居第二,以及最后9000w中差点被for超越,但是综合实力依旧排名第一。
赛事总结
以上的测试来看,无论时在浏览器环境还是在node环境中,这几个循环的效率排名名次都是一样的。
while
在两个环境中效率都是比较有明显的优势,因此如果在如此工作中,想要追求性能的情况下,能使用while循环的情况下可以优先考虑。
for
for循环算是大多数人最熟悉的循环它有着着灵活多变的写法,在遍历中也有不错的效率,,效率随着遍历的次数越多优势就越明显,在需要遍历次数很多且不能使用while的情况下,可以优先考虑。
forEach
forEach循环可能很多人在日常工作中最常写,因为比较简洁方便,遍历的效果很不错,特别是在遍历次数中上的情况下效率要比for循环还要好,在需要遍历次数中上且不能使用while的情况下,可以优先考虑。
for of
for of循环遍历的效率比forEach略低,因此正常遍历数据可以优先考虑上面三种,可以在遍历类数组中使用。
for in
for in循环并不适合遍历数组数据,因为在遍历数组数据的性能实在是太差了,不是万不得已千万不要使用,他的应用场景更多是遍历对象。
总结
这次的测试中发现循环在node环境中的效率不如在浏览器中的效率高(有可能是我的电脑本身性问题),
在遍历的数据量并不大且不追求极限性能的情况下并不需要太纠结选择除了for in循环外的其他循环方式,可以根据自己的熟悉程度来选择。
选择循环方式可以先根据自己的实际场景考虑,如果多个循环方式适合该场景,再根据效率选择。