前言
又到了大家喜欢的性能对比环节,这次我们来测试一下js遍历方法之间的性能差异,看完赶紧应用起来。
测试的方法包含:
- 普通for循环
- 优化for循环(缓存len)
- for in
- for of
- while (缓存len)
- do while (缓存len)
- 倒序for(缓存len)
- 倒序while (缓存len)
- map
- foreach
- reduce
- some
- filter
测试方法
const amount = 3000000;
const arr = new Array(amount).fill({name: 'CoderLiu', age: '8',location: '北京'} );
testFunction(arr)
function testFunction(array) {
function testFor() {
let newArray = []
console.time('testFor')
for (let i = 0; i < array.length; i++) {
newArray.push(array[i])
}
console.timeEnd('testFor')
}
testFor()
function testForLen() {
let newArray = []
console.time('testForLen')
for (let i = 0, len = array.length; i < len; i++) {
newArray.push(array[i])
}
console.timeEnd('testForLen')
}
testForLen()
function testForIn() {
let newArray = []
console.time('testForIn')
for (let i in array) {
newArray.push(array[i])
}
console.timeEnd('testForIn')
}
testForIn()
function testForOf() {
let newArray = []
console.time('testForOf')
for (let i of array) {
newArray.push(array[i])
}
console.timeEnd('testForOf')
}
testForOf()
function testWhileMinus() {
let newArray = []
let i = array.length;
console.time('testWhile--')
while (i--) {
newArray.push(array[i])
}
console.timeEnd('testWhile--')
}
testWhileMinus()
function testForlenMinus() {
let newArray = []
console.time('testForlen--')
for(let i = array.length; i--;) {
newArray.push(array[i])
}
console.timeEnd('testForlen--')
}
testForlenMinus()
function testWhile() {
let newArray = []
let i = 0
const len = array.length;
console.time('testWhile')
while (i < len) {
newArray.push(array[i])
i++
}
console.timeEnd('testWhile')
}
testWhile()
function testWhile() {
let newArray = []
let i = 0
const len = array.length;
console.time('testWhile')
while (i < len) {
newArray.push(array[i])
i++
}
console.timeEnd('testWhile')
}
testWhile()
function testDoWhile() {
let newArray = []
const len = array.length;
let i = 0
console.time('testDoWhile')
do {
newArray.push(array[i])
i++
} while (i < len);
console.timeEnd('testDoWhile')
}
testDoWhile()
function testMap() {
let newArray = []
console.time('testMap')
array.map((item) => {
newArray.push(item)
})
console.timeEnd('testMap')
}
testMap()
function testForeach() {
let newArray = []
console.time('testForeach')
array.forEach((item) => {
newArray.push(item)
})
console.timeEnd('testForeach')
}
testForeach()
function testFilter() {
let newArray = []
console.time('testFilter')
array.filter((item) => {
newArray.push(item)
})
console.timeEnd('testFilter')
}
testFilter()
function testSome() {
let newArray = []
console.time('testSome')
array.some((item) => {
newArray.push(item)
})
console.timeEnd('testSome')
}
testSome()
function testReduce() {
let newArray = []
console.time('testReduce')
array.reduce((all, a) => {
newArray.push(a)
}, 0)
console.timeEnd('testReduce')
}
testReduce()
}
结论
使用以上方法测试2组数据,测试内容为循环push对象,测试浏览器为chrome v106,数据量分别为30 和 3000000,对象为{name: 'CoderLiu', age: '8', location: '北京'}
循环次数30,取执行10次平均值:
testFor: 0.01904296875 ms
testForLen: 0.010009765625 ms
testForIn: 0.011962890625 ms
testForOf: 0.105224609375 ms
testWhile--: 0.007133203125 ms
testForlen--: 0.0068359375 ms
testWhile: 0.00732421875 ms
testDoWhile: 0.007080078125 ms
testMap: 0.01611328125 ms
testForeach: 0.011962890625 ms
testFilter: 0.01220703125 ms
testSome: 0.01123046875 ms
testReduce: 0.012939453125 ms
> 由于普通for循环可完全被优化for循环代替,所以以下所说的所有for循环都指优化for循环。
数据量较少时:
- 倒序for循环和do while最快,for of 极慢,未缓存length的for循环和
map相对较慢,其余写法相差不大。 - 数据量较少时不适合使用for of
- 普通for循环与优化for循环差异很大,使用for循环时记得缓存length
- 数据量较少时for in 循环还吃得消,但是还是不推荐使用,for in 会遍历原型上的属性
- 单纯循环推荐使用for循环、while、do while,且能倒序优先使用倒序循环,倒序for循环与倒序while差距不大,但是for循环可以执行完成后会销毁变量,while则一直引用外部变量,for循环相对内存占用更少
- 根据业务需求使用map,forEach等也完全没问题,因为数据量较少对性能影响很微小
forlen-- > while--// 倒序循环基本不相上下
do while > while > forlen// 正序循环
some > forEach > filter > reduce > map// 数组方法,map最慢,其他不相上下,因为map要额外创建数组
循环次数300000,取执行10次平均值:
testFor: 171.20703125 ms
testForLen: 132.240966796875 ms
testForIn: 1282.339111328125 ms
testForOf: 403.389892578125 ms
testWhile--: 62.822021484375 ms
testForlen--: 54.20703125 ms
testWhile: 80.328125 ms
testDoWhile: 66.9970703125 ms
testMap: 420.965087890625 ms
testForeach: 135.4150390625 ms
testFilter: 140.927001953125 ms
testSome: 127.870849609375 ms
testReduce: 155.22314453125 ms
数据量较大时:
- 数据量增大时,for in 耗时明显一骑绝尘, for of 和 map 紧随其后,依旧很慢
- 数据量增大时 while 比 forlen 快的更明显了
forlen-- > while--// 倒序循环基本不相上下
do while > while > forlen// 正序循环,while比forlen快的更明显了
some > forEach > filter > reduce > map// 数组方法,map最慢,其他依旧不相上下
总结
以上结论仅供参考,测试方法并不科学,结果并不适用于所有运行环境,大家看完此文心里大致有个数就可以了,使用时也不要太纠结,如果不是库开发者的话,或者一些非需要极致优化的场景下显然可读性可维护性更重要。
更多性能优化实践可戳如何使用链式属性表达式取值和赋值(高性能版)
感谢你花费宝贵的时间阅读本文,如果本文给了你一点点帮助或者启发,还请三连支持一下,点赞、关注、收藏,作者会持续与发家分享更多干货。