最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Is there any real benefit for using javascript Array reduce() method? - Stack Overflow

programmeradmin0浏览0评论

Most use cases of the reduce() method can be easily rewritten with a for loop. And testing on JSPerf shows that reduce() is usually 60%-75% slower, depending on the operations performed inside each iteration.

Is there any real reason to use reduce() then, other than being able to write code in a 'functional style'? If you can have a 60% performance gain by writing just a little bit more code, why would you ever use reduce()?

EDIT: In fact, other functional methods like forEach() and map() all show similar performance, being at least 60% slower than simple for loops.

Here's a link to the JSPerf test (with function calls): forloop vs forEach

Most use cases of the reduce() method can be easily rewritten with a for loop. And testing on JSPerf shows that reduce() is usually 60%-75% slower, depending on the operations performed inside each iteration.

Is there any real reason to use reduce() then, other than being able to write code in a 'functional style'? If you can have a 60% performance gain by writing just a little bit more code, why would you ever use reduce()?

EDIT: In fact, other functional methods like forEach() and map() all show similar performance, being at least 60% slower than simple for loops.

Here's a link to the JSPerf test (with function calls): forloop vs forEach

Share Improve this question edited Mar 14, 2012 at 5:16 Evan You asked Mar 9, 2012 at 5:36 Evan YouEvan You 2,7111 gold badge26 silver badges15 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 7

The performance of the methods may vary depending on the size of the data. Speed ​​is also affected by compiler optimization and data warm-up. Therefore on small data for of wins, and on big reduce insignificantly wins.

You can see for yourself by running the test:

const LOOP = 3

test(dataGenerator(5))
test(dataGenerator(500))
test(dataGenerator(50000))
test(dataGenerator(500000))
test(dataGenerator(5000000))

function test(dataSet) {
    let sum

    console.log('Data length:', dataSet.length)

    for (let x = 0; x < LOOP; x++) {
        sum = 0
        console.time(`${x} reduce`)
        sum = dataSet.reduce((s, d) => s += d.data, 0)
        console.timeEnd(`${x} reduce`)
    }

    for (let x = 0; x < LOOP; x++) {
        sum = 0
        console.time(`${x} map`)
        dataSet.map((i) => sum += i.data)
        console.timeEnd(`${x} map`)
    }

    for (let x = 0; x < LOOP; x++) {
        sum = 0
        console.time(`${x} for loop`)
        for (let i = 0; i < dataSet.length; i++) {
            sum += dataSet[i].data
        }
        console.timeEnd(`${x} for loop`)
    }

    for (let x = 0; x < LOOP; x++) {
        sum = 0
        console.time(`${x} for reverse`)
        for (let i = dataSet.length; i--;) {
            sum += dataSet[i].data
        }
        console.timeEnd(`${x} for reverse`)
    }

    for (let x = 0; x < LOOP; x++) {
        sum = 0
        console.time(`${x} for of`)
        for (const item of dataSet) {
            sum += item.data
        }
        console.timeEnd(`${x} for of`)
    }

    for (let x = 0; x < LOOP; x++) {
        sum = 0
        console.time(`${x} for each`)
        dataSet.forEach(element => {
            sum += element.data
        })
        console.timeEnd(`${x} for each`)
    }

    console.log()
}

function dataGenerator(rows) {
    const dataSet = []
    for (let i = 0; i < rows; i++) {
        dataSet.push({id: i, data: Math.floor(100 * Math.random())})
    }
    return dataSet
}

These are the results of a performance test on my laptop. for loop does not work stably unlike for reverse and for of.

➜  node reduce_vs_for.js 
Data length: 5
0 reduce: 0.127ms
1 reduce: 0.008ms
2 reduce: 0.006ms
0 map: 0.036ms
1 map: 0.007ms
2 map: 0.018ms
0 for loop: 0.005ms
1 for loop: 0.014ms
2 for loop: 0.004ms
0 for reverse: 0.009ms
1 for reverse: 0.005ms
2 for reverse: 0.004ms
0 for of: 0.008ms
1 for of: 0.004ms
2 for of: 0.004ms
0 for each: 0.046ms
1 for each: 0.003ms
2 for each: 0.003ms

Data length: 500
0 reduce: 0.031ms
1 reduce: 0.027ms
2 reduce: 0.026ms
0 map: 0.039ms
1 map: 0.036ms
2 map: 0.033ms
0 for loop: 0.029ms
1 for loop: 0.028ms
2 for loop: 0.028ms
0 for reverse: 0.027ms
1 for reverse: 0.026ms
2 for reverse: 0.026ms
0 for of: 0.051ms
1 for of: 0.063ms
2 for of: 0.051ms
0 for each: 0.030ms
1 for each: 0.030ms
2 for each: 0.027ms

Data length: 50000
0 reduce: 1.986ms
1 reduce: 1.017ms
2 reduce: 1.017ms
0 map: 2.142ms
1 map: 1.352ms
2 map: 1.310ms
0 for loop: 2.407ms
1 for loop: 12.170ms
2 for loop: 0.246ms
0 for reverse: 0.226ms
1 for reverse: 0.225ms
2 for reverse: 0.223ms
0 for of: 0.217ms
1 for of: 0.213ms
2 for of: 0.215ms
0 for each: 0.391ms
1 for each: 0.409ms
2 for each: 1.020ms

Data length: 500000
0 reduce: 1.920ms
1 reduce: 1.837ms
2 reduce: 1.860ms
0 map: 13.140ms
1 map: 12.762ms
2 map: 14.584ms
0 for loop: 15.325ms
1 for loop: 2.295ms
2 for loop: 2.014ms
0 for reverse: 2.163ms
1 for reverse: 2.138ms
2 for reverse: 2.182ms
0 for of: 1.990ms
1 for of: 2.009ms
2 for of: 2.108ms
0 for each: 2.226ms
1 for each: 2.583ms
2 for each: 2.238ms

Data length: 5000000
0 reduce: 18.763ms
1 reduce: 17.155ms
2 reduce: 26.592ms
0 map: 145.415ms
1 map: 135.946ms
2 map: 144.325ms
0 for loop: 29.273ms
1 for loop: 28.365ms
2 for loop: 21.131ms
0 for reverse: 21.301ms
1 for reverse: 27.779ms
2 for reverse: 29.077ms
0 for of: 19.094ms
1 for of: 19.338ms
2 for of: 26.567ms
0 for each: 22.456ms
1 for each: 26.224ms
2 for each: 20.769ms
  • You might want scoping. For example you might want to make callback functions or have references to javascript objects. For more information, see why javascript is not blocked scoped. [edit: modern javascript now supports let variables. Back before ESv6, when you declared a var variable, it got hoisted as if it was written at the top of the function codeblock, so often you had to write bodies of for-loops as functions. This following still applies though:] If you had a function written, might as well use functional style unless it's a significant bottleneck.
  • Your code does not always need to run at full machine speed. You may not even be optimizing code in the bottleneck.
  • Additionally you do not provide your "testing on JSPerf" so we can critique it. For example if you already have a reduction function (or map or forEach function), then I bet the performance would be on-par. Even if not, the testing methodology may be flawed, especially given that many browsers may optimize differently or have different function-call overhead.

sidenote: this is a valid performance comparison between syntax, but an invalid performance comparison in when syntax is not the question at hand:

myArray.map(function(x){return x+1})

// ...versus...

for(var i=0; i<myArray.length; i++) {
    myArray[i] = myArray[i]+1;
}

This would be a valid performance comparison:

myArray.forEach(function(x){return x+1})

// ...versus...

var plusOne = function(x){return x+1};
for(var i=0; i<myArray.length; i++) {
    plusOne(myArray[i]);
}

// (may need a side-effect if the compiler is smart enough to optimize this)

(Also in reply to your edit: .forEach() and .map() provide much more clarity, and avoid the need for explicit loop int i=0; i<array.length; i++ arguments.)

发布评论

评论列表(0)

  1. 暂无评论