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

Performance implications of using Functional style Javascript vs "procedural" - Stack Overflow

programmeradmin4浏览0评论

Has anybody done benchmarking, or can link to an article on this subject? Particularly interested in IE results, since usually JS performance is not a problem in other browsers.

I would like to know how much slower it is to do something like:

var numbers = [1, 2, 3, 4, 5, 6, 7];
var results = numbers.map(function() { 
  // do some stuff
});

instead of the typical:

var numbers = [1, 2, 3, 4, 5, 6, 7];
var results = [];

for (var i = 0; i < numbers.length; i++) {
  var number = numbers[i];
  var result;
  // do some stuff
  results.push(result);
}

I obviously prefer the functional style, but I assume the extra overhead of calling an extra function for each item could slow things down with big collections.

Thanks!

Has anybody done benchmarking, or can link to an article on this subject? Particularly interested in IE results, since usually JS performance is not a problem in other browsers.

I would like to know how much slower it is to do something like:

var numbers = [1, 2, 3, 4, 5, 6, 7];
var results = numbers.map(function() { 
  // do some stuff
});

instead of the typical:

var numbers = [1, 2, 3, 4, 5, 6, 7];
var results = [];

for (var i = 0; i < numbers.length; i++) {
  var number = numbers[i];
  var result;
  // do some stuff
  results.push(result);
}

I obviously prefer the functional style, but I assume the extra overhead of calling an extra function for each item could slow things down with big collections.

Thanks!

Share Improve this question edited Aug 12, 2010 at 2:57 adamJLev asked Aug 9, 2010 at 15:47 adamJLevadamJLev 14k11 gold badges62 silver badges65 bronze badges 5
  • May be a moot point, but IE < 9 doesn't even implement [].map. You're patching Array.prototype yourself are you? – Crescent Fresh Commented Aug 9, 2010 at 16:00
  • 2 Joe Armstrong, of Erlang fame, always gives the advice when asked questions like this that programmers should write the most beautiful programs they can. Code the way you want your ideas to be reflected - using good and proper basic algorithms, of course! - and let the guys souping up V8, Tracemonkey, and JScript deal with making function calls faster. Don't bog yourself down with code that, in a year, won't actually make things faster anyway. – Pointy Commented Aug 9, 2010 at 16:04
  • @Crescent yeah patching Array.prototype, or using something like this: documentcloud.github./underscore – adamJLev Commented Aug 9, 2010 at 16:30
  • 1 @Pointy I like beautiful code, but after working on a project where my fulltime job was pretty much "fixing this code so that it's not unbearably slow in IE", now that I'm starting fresh on what's going to be a major webapp (think Gmail), I don't want to make mistakes. – adamJLev Commented Aug 9, 2010 at 16:30
  • @Inifinity, it's unwise to speak in generalities but I agree with Pointy and the point that he's making. A lot of times if something is unbearably slow it's not the libraries that are the issue--it's things like the code reading a constant value on every pass through a loop and dumb things of this sort. Of course, I'm making a huge generalization. :-) By the way--this might help you in your work: whitefrost./documents/html/technical/dhtml/jsprof.html – Onorio Catenacci Commented Aug 10, 2010 at 17:17
Add a ment  | 

4 Answers 4

Reset to default 6

TL;DR: The older your syntax, the faster. Avoid functional programming when you're optimizing for speed.

I decided to e up with a benchmark that would include the mon things that you might do with functional programming, which just produced some aggregations. The resulting benchmark can be run here. The following results are from late 2020, but by the time you're reading this, maybe some optimizations or something have been done, you can re-test it with this link, but if that link is dead, the code is also pasted below. I've used the results from Chrome, but while some browsers run things faster than others, they all maintain the same performance ordering. Turns out Firefox is way slower as of this writing, like, Chrome is 5x faster than Firefox. Edge is just as fast as Chrome. Safari is also just as fast as Chrome. Node is also just as fast as Chrome. Since Chrome, Safari, and node all run on the v8 engine, I suspect they'll always be the same speed:

https://jsbench.me/dvkgymlimu/1

The first function 'aggregate_functional', uses all the newest syntax, spread operators, reduce, etc. It is by far the slowest, running at around 10M ops/sec. Given that this is the slowest, but still runs a crazy 10 million times every second, I think this proves that the argument is moot for all but the most extreme cases. If 10 million times per second isn't fast enough for you, then read on.

The next function uses the "of" loop, and is FOUR TIMES FASTER than the functional version. I wasn't really expecting this level of performance boost.

The last function 'aggregate_imperative_idx', uses "old" JavaScript things, no spread operator, no "of" loop, just a indexed loop. If not for the "let" and "const" keywords, it should run on Netscape Navigator. I was happy to find that using "var" did not improve performance. That would have made me sad. It ended up being 8.2x faster than the functional implementation, at 82M ops/sec.



function aggregate_functional (numbers) {
  if (numbers.length == 0) {
    throw new Error("aggregate() requires at least one number")
  }
  const sum = numbers.reduce((s, n) => s += n)
  let min = Math.min(...numbers)
  let max = Math.max(...numbers)
  const average = sum / numbers.length
  return {
    sum,
    average,
    min,
    max,
  }
}

function aggregate_imperative (numbers) {
  if (numbers.length == 0) {
    throw new Error("aggregate() requires at least one number")
  }
  let sum = 0
  let min = numbers[0]
  let max = numbers[0]
  for (const val of numbers) {
    if (val < min) min = val
    if (val > max) max = val
    sum += val
  }
  const average = sum / numbers.length
  return {
    sum,
    average,
    min,
    max,
  }
}

function aggregate_imperative_idx (numbers) {
  if (numbers.length == 0) {
    throw new Error("aggregate() requires at least one number")
  }
  let sum = 0
  let min = numbers[0]
  let max = numbers[0]
  for (let i = 0; i < numbers.length; i++) {
    const val = numbers[i]
    if (val < min) min = val
    if (val > max) max = val
    sum += val
  }
  const average = sum / numbers.length
  return {
    sum,
    average,
    min,
    max,
  }
}

Not content with the lack of proof on this subject, I wrote a short benchmark. It's far from perfect but I think it answers the question.

I ran it in IE 8/win, and while the functional method is slower, it's never going to be the bottleneck in real code. (Unless you're doing stuff that you shouldn't be doing in the client anyway)

So I will be using the cleaner approach whenever I have to pick (yay)

(Best of 5)
Functional method: 453ms
Old school approach: 156ms

Array.prototype.map = function(fun) {
  var len = this.length >>> 0;
  if (typeof fun != "function")
    throw new TypeError();

  var res = new Array(len);
  var thisp = arguments[1];
  for (var i = 0; i < len; i++) {
    if (i in this)
      res[i] = fun.call(thisp, this[i], i, this);
  }

  return res;
};

/**
 *
 *
 */

// Initialize test array
var numbers = [];
for (var i = 0; i < 100000; i++) numbers.push(i);

// Benchmark!
var start = +new Date();

// Test 1
var results1 = numbers.map(function(num) {
  return num + num;
});

alert('1. Functional map:' + (start - new Date()));
start = +new Date();

// Test 2
var results2 = [];
for (var j = 0, l = numbers.length; j < l; j++) {
  var num = numbers[j];
  results2.push(num + num)
}

alert('1. Old school approach' + (start - new Date()));
start = +new Date();

This one is really interesting:

http://www.slideshare/madrobby/extreme-javascript-performance

However, in ECMAScript5-ready JS engines with native Array.map(), things may change drastically.

This is very interesting too:

http://documentcloud.github./underscore/test/test.html

The results vary from browser to browser, because underscore tries to use the native alternative where available.

发布评论

评论列表(0)

  1. 暂无评论