Why are these Javascript for loops significantly slower on Firefox then Chrome / Safari?

怎甘沉沦 提交于 2020-12-01 09:56:19

问题


I was messing around with the benchmark site jfprefs and created my own benchmark at http://jsperf.com/prefix-or-postfix-increment/9.

The benchmarks are variations of Javascript for loops, using prefix and postfix incrementors and the Crockford jslint style of not using an in place incrementor.

for (var index = 0, len = data.length; index < len; ++index) {
  data[index] = data[index] * 2;
}

for (var index = 0, len = data.length; index < len; index++) {
  data[index] = data[index] * 2;
}

for (var index = 0, len = data.length; index < len; index += 1) {
  data[index] = data[index] * 2;
}

After getting the numbers from a couple of runs of the benchmark, I noticed that Firefox is doing about 15 operations per second on average and Chrome is doing around 300.

benchmark results

I thought JaegerMonkey and v8 were fairly comparable in terms of speed? Are my benchmarks flawed somehow, is Firefox doing some kind of throttling here or is the gap really that large between the performance of the Javascript interpreters?

UPDATE: Thanks to jfriend00, I've concluded the difference in performance is not entirely due to the loop iteration, as seen in this version of the test case. As you can see Firefox is slower, but not as much of a gap as we see in the initial test case.

So why is the statement,

data[index] = data[index] * 2;

So much slower on Firefox?


回答1:


Arrays are tricky in JavaScript. The way you create them, how you fill them (and with what values) can all affect their performance.

There are two basic implementations that engines use. The simplest, most obvious one is a contiguous block of memory (just like a C array, with some metadata, like the length). It's the fastest way, and ideally the implementation you want in most cases.

The problem is, arrays in JavaScript can grow very large just by assigning to an arbitrary index, leaving "holes". For example, if you have a small array:

var array = [1,2,3];

and you assign a value to a large index:

array[1000000] = 4;

you'll end up with an array like this:

[1, 2, 3, undefined, undefined, undefined, ..., undefined, 4]

To save memory, most runtimes will convert array into a "sparse" array. Basically, a hash table, just like regular JS objects. Once that happens, reading or writing to an index goes from simple pointer arithmetic to a much more complicated algorithm, possibly with dynamic memory allocation.

Of course, different runtimes use different heuristics to decide when to convert from one implementation to another, so in some cases, optimizing for Chrome, for example, can hurt performance in Firefox.

In your case, my best guess is that filling the array backwards is causing Firefox to use a sparse array, making it slower.




回答2:


I hate to give you such a simple answer, but pretty simply: instruction branching: http://igoro.com/archive/fast-and-slow-if-statements-branch-prediction-in-modern-processors/

From what I get from the benchmark, there's something under the hood in these engines that is giving the instruction prediction features of the processor hell.



来源:https://stackoverflow.com/questions/12327958/why-are-these-javascript-for-loops-significantly-slower-on-firefox-then-chrome

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!