JS遍历13种循环方法性能大比拼:for/while/for in/for of/map/foreach...

910 阅读3分钟

前言

又到了大家喜欢的性能对比环节,这次我们来测试一下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最慢,其他依旧不相上下

总结

以上结论仅供参考,测试方法并不科学,结果并不适用于所有运行环境,大家看完此文心里大致有个数就可以了,使用时也不要太纠结,如果不是库开发者的话,或者一些非需要极致优化的场景下显然可读性可维护性更重要。

更多性能优化实践可戳如何使用链式属性表达式取值和赋值(高性能版)

感谢你花费宝贵的时间阅读本文,如果本文给了你一点点帮助或者启发,还请三连支持一下,点赞、关注、收藏,作者会持续与发家分享更多干货