Why is this code so much faster (relatively) in IE7?
Here's some code that I ran through jsperf to assess its performance. The first test (named EvalLengthBefore++ in the images below) is the way I would consider normally looping through the elements of an array:
var arr = ;
for (var x = 0; x < 1000; x++) {
arr.push(Math.random());
}
var len = arr.length;
for (var y = 0; y < len; y++) {
//do some maths
var el = arr[y];
el++; //meaningless operation
}
The second test (named InfiniteLoopWithBreak in the images below) is the method I found in some code that is supposed to to be run in IE7 (it's part of a CSS fallback):
var arr = ;
for (var x = 0; x < 1000; x++) {
arr.push(Math.random());
}
for (var y = 0;; y += 1) {
//do some maths
var el = arr[y];
if (!el) {
break;
}
el++;
}
In modern browsers, the second method is much slower, which is kind of what I expected. However in IE7 it is just as fast, occasionally faster, in the jsperf tests:
Test results in Chrome:
Test results in IE7
Here are the jsperf tests if you want to run them yourselves.
Why is the second code snippet faster than the rest in IE7?
javascript performance array
add a comment |
Here's some code that I ran through jsperf to assess its performance. The first test (named EvalLengthBefore++ in the images below) is the way I would consider normally looping through the elements of an array:
var arr = ;
for (var x = 0; x < 1000; x++) {
arr.push(Math.random());
}
var len = arr.length;
for (var y = 0; y < len; y++) {
//do some maths
var el = arr[y];
el++; //meaningless operation
}
The second test (named InfiniteLoopWithBreak in the images below) is the method I found in some code that is supposed to to be run in IE7 (it's part of a CSS fallback):
var arr = ;
for (var x = 0; x < 1000; x++) {
arr.push(Math.random());
}
for (var y = 0;; y += 1) {
//do some maths
var el = arr[y];
if (!el) {
break;
}
el++;
}
In modern browsers, the second method is much slower, which is kind of what I expected. However in IE7 it is just as fast, occasionally faster, in the jsperf tests:
Test results in Chrome:
Test results in IE7
Here are the jsperf tests if you want to run them yourselves.
Why is the second code snippet faster than the rest in IE7?
javascript performance array
8
Not sure if this belongs to codereview.SE but it does look like a pretty interesting question.
– Josay
Oct 3 '13 at 15:20
@Josay, I debated for a while whether it was more suited to here or Stack Overflow, but settled for here in the end. Happy to have the question migrated if the mods feel it would be more suitable over at SE.
– Andy F
Oct 3 '13 at 15:22
Yeah, I'd wait for the mods to decide. However, this doesn't quite fit "understanding code snippets" because because you already know what's happening. You just want to know why.
– Jamal♦
Oct 3 '13 at 17:14
would be interesting to test alsofor (var el, y = 0; el = arr[y]; y++) { el++; }
– Stuart
Oct 3 '13 at 19:29
1
@AndyF: A very interesting question, I must say. Sadly, I think programmers.stackexchange or (though borderline) even computerscience.stackexchange. Anyway, I've posted a (rather verbose) answer here anyway... ;P
– Elias Van Ootegem
Oct 4 '13 at 10:09
add a comment |
Here's some code that I ran through jsperf to assess its performance. The first test (named EvalLengthBefore++ in the images below) is the way I would consider normally looping through the elements of an array:
var arr = ;
for (var x = 0; x < 1000; x++) {
arr.push(Math.random());
}
var len = arr.length;
for (var y = 0; y < len; y++) {
//do some maths
var el = arr[y];
el++; //meaningless operation
}
The second test (named InfiniteLoopWithBreak in the images below) is the method I found in some code that is supposed to to be run in IE7 (it's part of a CSS fallback):
var arr = ;
for (var x = 0; x < 1000; x++) {
arr.push(Math.random());
}
for (var y = 0;; y += 1) {
//do some maths
var el = arr[y];
if (!el) {
break;
}
el++;
}
In modern browsers, the second method is much slower, which is kind of what I expected. However in IE7 it is just as fast, occasionally faster, in the jsperf tests:
Test results in Chrome:
Test results in IE7
Here are the jsperf tests if you want to run them yourselves.
Why is the second code snippet faster than the rest in IE7?
javascript performance array
Here's some code that I ran through jsperf to assess its performance. The first test (named EvalLengthBefore++ in the images below) is the way I would consider normally looping through the elements of an array:
var arr = ;
for (var x = 0; x < 1000; x++) {
arr.push(Math.random());
}
var len = arr.length;
for (var y = 0; y < len; y++) {
//do some maths
var el = arr[y];
el++; //meaningless operation
}
The second test (named InfiniteLoopWithBreak in the images below) is the method I found in some code that is supposed to to be run in IE7 (it's part of a CSS fallback):
var arr = ;
for (var x = 0; x < 1000; x++) {
arr.push(Math.random());
}
for (var y = 0;; y += 1) {
//do some maths
var el = arr[y];
if (!el) {
break;
}
el++;
}
In modern browsers, the second method is much slower, which is kind of what I expected. However in IE7 it is just as fast, occasionally faster, in the jsperf tests:
Test results in Chrome:
Test results in IE7
Here are the jsperf tests if you want to run them yourselves.
Why is the second code snippet faster than the rest in IE7?
javascript performance array
javascript performance array
edited Oct 3 '13 at 16:56
200_success
128k15152413
128k15152413
asked Oct 3 '13 at 15:15
Andy F
1604
1604
8
Not sure if this belongs to codereview.SE but it does look like a pretty interesting question.
– Josay
Oct 3 '13 at 15:20
@Josay, I debated for a while whether it was more suited to here or Stack Overflow, but settled for here in the end. Happy to have the question migrated if the mods feel it would be more suitable over at SE.
– Andy F
Oct 3 '13 at 15:22
Yeah, I'd wait for the mods to decide. However, this doesn't quite fit "understanding code snippets" because because you already know what's happening. You just want to know why.
– Jamal♦
Oct 3 '13 at 17:14
would be interesting to test alsofor (var el, y = 0; el = arr[y]; y++) { el++; }
– Stuart
Oct 3 '13 at 19:29
1
@AndyF: A very interesting question, I must say. Sadly, I think programmers.stackexchange or (though borderline) even computerscience.stackexchange. Anyway, I've posted a (rather verbose) answer here anyway... ;P
– Elias Van Ootegem
Oct 4 '13 at 10:09
add a comment |
8
Not sure if this belongs to codereview.SE but it does look like a pretty interesting question.
– Josay
Oct 3 '13 at 15:20
@Josay, I debated for a while whether it was more suited to here or Stack Overflow, but settled for here in the end. Happy to have the question migrated if the mods feel it would be more suitable over at SE.
– Andy F
Oct 3 '13 at 15:22
Yeah, I'd wait for the mods to decide. However, this doesn't quite fit "understanding code snippets" because because you already know what's happening. You just want to know why.
– Jamal♦
Oct 3 '13 at 17:14
would be interesting to test alsofor (var el, y = 0; el = arr[y]; y++) { el++; }
– Stuart
Oct 3 '13 at 19:29
1
@AndyF: A very interesting question, I must say. Sadly, I think programmers.stackexchange or (though borderline) even computerscience.stackexchange. Anyway, I've posted a (rather verbose) answer here anyway... ;P
– Elias Van Ootegem
Oct 4 '13 at 10:09
8
8
Not sure if this belongs to codereview.SE but it does look like a pretty interesting question.
– Josay
Oct 3 '13 at 15:20
Not sure if this belongs to codereview.SE but it does look like a pretty interesting question.
– Josay
Oct 3 '13 at 15:20
@Josay, I debated for a while whether it was more suited to here or Stack Overflow, but settled for here in the end. Happy to have the question migrated if the mods feel it would be more suitable over at SE.
– Andy F
Oct 3 '13 at 15:22
@Josay, I debated for a while whether it was more suited to here or Stack Overflow, but settled for here in the end. Happy to have the question migrated if the mods feel it would be more suitable over at SE.
– Andy F
Oct 3 '13 at 15:22
Yeah, I'd wait for the mods to decide. However, this doesn't quite fit "understanding code snippets" because because you already know what's happening. You just want to know why.
– Jamal♦
Oct 3 '13 at 17:14
Yeah, I'd wait for the mods to decide. However, this doesn't quite fit "understanding code snippets" because because you already know what's happening. You just want to know why.
– Jamal♦
Oct 3 '13 at 17:14
would be interesting to test also
for (var el, y = 0; el = arr[y]; y++) { el++; }
– Stuart
Oct 3 '13 at 19:29
would be interesting to test also
for (var el, y = 0; el = arr[y]; y++) { el++; }
– Stuart
Oct 3 '13 at 19:29
1
1
@AndyF: A very interesting question, I must say. Sadly, I think programmers.stackexchange or (though borderline) even computerscience.stackexchange. Anyway, I've posted a (rather verbose) answer here anyway... ;P
– Elias Van Ootegem
Oct 4 '13 at 10:09
@AndyF: A very interesting question, I must say. Sadly, I think programmers.stackexchange or (though borderline) even computerscience.stackexchange. Anyway, I've posted a (rather verbose) answer here anyway... ;P
– Elias Van Ootegem
Oct 4 '13 at 10:09
add a comment |
4 Answers
4
active
oldest
votes
The short answer:
In your code the arr.length
is the major bottleneck. Simply because of the differences between the various implementations of JavaScript. Not only the implementations differ, but also what the engines actually do prior to executing your code.
Why do I think this: simple:
for([[expr evaluated at start of loop]];
[[expr re-evaluated on each iteration + 1(end of loop)]];
[[expr evaluated for each iteration +1(end of loop)]]
)
The cases that are fastest on IE7 are those where the conditional expression in the for-loop is either missing or is simply comparing the values of 2 variables.
The long answer, without focussing on arr.length
, but keep in mind that here, you're getting a property of an object, that is, sort-of, inherited from the prototype.
The reason why is simply because of how Chrome's V8 compiles the code, and how the Object[[GetProperty]]
is implemented. Since JS arrays are just augmented objects (Array instanceof Object
is true
), getting a value from an array is, essentially the same as someObj.someProp
.
Most JS implementations use either a HashMap or HashTable for the objects. Chrome's V8 engine, is a bit of an odd one out, in a couple of crucial ways.
FF's SpiderMonkey/*Monkey engines compile JS code to intermediate byte-code, that runs on a virtual machine.
Their Rhino engine compiles JS to Java, which is also a VM environment. Cf the hybrid model in the img below
JS "engines" of old didn't even go that far, they were just parse-and-execute things. They did no or very little optimization or reflection on the code they were asked to parse.
V8 does things a bit different: it parses, optimizes and compiles the resulting AST (Abstract Syntax Tree) straight into machine-executable code. No byte-code virtual-machine stuff to hold you back:
So, Chrome's V8 compiles to machine code, which cuts down overall execution time (in most cases). In addition to that, the V8 engine does not use a HashTable for object properties. It creates classes:
To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes.
What does this mean for arr.length
:
//V8:
arr = ;//creates class, that has length property, value 0
arr.push(123);//arr points to class with property 0 = 123, length = 1
That means that, arr.length
or arr[0]
both are simple, atomic operations. In terms of time-complexity, they are as close as makes no difference both: O(1). Now, I'm not familiar with the internals of IE's JScript engine, but I'm prepared to take a punt on how arr.length
works:
arr.length;//->arr @instancelevel->search(length)
//
==>arr.prototype->search(length)
//
==> magic property, probably does something like:
return max(@instance.keys) +1
Now, this may range anywhere from pretty accurate to down-right absurd, but the principle stands: getting the length property from an array on engines that don't create classes for instances, is not atomic, and therefore slower.
Sadly, because of MS's software being closed source, I can't tell you what kind of AST the parser churns out, nor what the engine then does with that AST. You'll have to get friendly with someone working in Redmond, or send a very polite email, requesting more info (don't expect an answer, though :-P).
So, V8 compiles the AST directly to machine-executable code, and creates classes to speedup property. In theory, accessing a property in JS, running on V8 should be almost as fast as C++ code. In theory, that is :P.
Internet Explorer's JScript engine, especially IE7, is quite dated. It doesn't do optimization very well. It doesn't compile JS as well as modern day engines do.
I can't find the resource ATM, but I also seem to remember that IE's JScript implementation of objects was, in fact, rather lacking, too. I seem to recall it didn't even use a full-blown HashTable for its objects, which would explain why someArray.length
takes ages (since it requires a prototype lookup).
Read more here.
add a comment |
Since you asked this question here rather than on Stack Overflow, I'm going to propose this countdown iteration:
for (var y = arr.length - 1; y >= 0; --y) {
//do some maths
var el = arr[y];
el++;
}
The advantages are:
- You only calculate
arr.length
once, and do so without introducing a temporary variable - Each iteration, you compare
y
with zero. To compare with any other number, the CPU would first have to load both values into registers before executing the conditional branch instruction. To compare against zero, only the value ofy
needs to be loaded in a register; there is a special instruction for comparing against zero and conditionally branching.
That said, the performance gain by iterating backward instead of forward is negligible, and you should avoid the countdown technique if
- The processing of an element depends on the value of another element
- The processing of an element could fail — premature termination of the loop would be weird if the partial results are at the end of the array
add a comment |
To start with, it might be that IE7 is so slow, you can't really tell the differences with such small numbers. Another factor might be that "length" calculation is really slow on an array this size (well, back then ...) and that array access is "optimized" (at least better, and doesn't hurt much more than static property access).
But I think that IE7's just too slow for us to notice.
add a comment |
First of all, microbenchmarks like these don't really tell the whole story. It may only be "fast" or "slow" in this case. In real-world scenarios, it may tell another story (like when you have to deal with stuff other than just arrays).
Another thing is, with such small numbers in the IE tests... you can't really say it's fast :D
Another thing is (and most likely this would be the cause of the great divide in Chrome) is that modern JS compilers tend to optimize "hot code". Other forms of code are internally faster as well due to the browser's implementation of operations.
So in this case, case 2 and case 4 in Chrome might have been optimized internally, whereas case 3 might have been faster for IE7.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f32186%2fwhy-is-this-code-so-much-faster-relatively-in-ie7%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
The short answer:
In your code the arr.length
is the major bottleneck. Simply because of the differences between the various implementations of JavaScript. Not only the implementations differ, but also what the engines actually do prior to executing your code.
Why do I think this: simple:
for([[expr evaluated at start of loop]];
[[expr re-evaluated on each iteration + 1(end of loop)]];
[[expr evaluated for each iteration +1(end of loop)]]
)
The cases that are fastest on IE7 are those where the conditional expression in the for-loop is either missing or is simply comparing the values of 2 variables.
The long answer, without focussing on arr.length
, but keep in mind that here, you're getting a property of an object, that is, sort-of, inherited from the prototype.
The reason why is simply because of how Chrome's V8 compiles the code, and how the Object[[GetProperty]]
is implemented. Since JS arrays are just augmented objects (Array instanceof Object
is true
), getting a value from an array is, essentially the same as someObj.someProp
.
Most JS implementations use either a HashMap or HashTable for the objects. Chrome's V8 engine, is a bit of an odd one out, in a couple of crucial ways.
FF's SpiderMonkey/*Monkey engines compile JS code to intermediate byte-code, that runs on a virtual machine.
Their Rhino engine compiles JS to Java, which is also a VM environment. Cf the hybrid model in the img below
JS "engines" of old didn't even go that far, they were just parse-and-execute things. They did no or very little optimization or reflection on the code they were asked to parse.
V8 does things a bit different: it parses, optimizes and compiles the resulting AST (Abstract Syntax Tree) straight into machine-executable code. No byte-code virtual-machine stuff to hold you back:
So, Chrome's V8 compiles to machine code, which cuts down overall execution time (in most cases). In addition to that, the V8 engine does not use a HashTable for object properties. It creates classes:
To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes.
What does this mean for arr.length
:
//V8:
arr = ;//creates class, that has length property, value 0
arr.push(123);//arr points to class with property 0 = 123, length = 1
That means that, arr.length
or arr[0]
both are simple, atomic operations. In terms of time-complexity, they are as close as makes no difference both: O(1). Now, I'm not familiar with the internals of IE's JScript engine, but I'm prepared to take a punt on how arr.length
works:
arr.length;//->arr @instancelevel->search(length)
//
==>arr.prototype->search(length)
//
==> magic property, probably does something like:
return max(@instance.keys) +1
Now, this may range anywhere from pretty accurate to down-right absurd, but the principle stands: getting the length property from an array on engines that don't create classes for instances, is not atomic, and therefore slower.
Sadly, because of MS's software being closed source, I can't tell you what kind of AST the parser churns out, nor what the engine then does with that AST. You'll have to get friendly with someone working in Redmond, or send a very polite email, requesting more info (don't expect an answer, though :-P).
So, V8 compiles the AST directly to machine-executable code, and creates classes to speedup property. In theory, accessing a property in JS, running on V8 should be almost as fast as C++ code. In theory, that is :P.
Internet Explorer's JScript engine, especially IE7, is quite dated. It doesn't do optimization very well. It doesn't compile JS as well as modern day engines do.
I can't find the resource ATM, but I also seem to remember that IE's JScript implementation of objects was, in fact, rather lacking, too. I seem to recall it didn't even use a full-blown HashTable for its objects, which would explain why someArray.length
takes ages (since it requires a prototype lookup).
Read more here.
add a comment |
The short answer:
In your code the arr.length
is the major bottleneck. Simply because of the differences between the various implementations of JavaScript. Not only the implementations differ, but also what the engines actually do prior to executing your code.
Why do I think this: simple:
for([[expr evaluated at start of loop]];
[[expr re-evaluated on each iteration + 1(end of loop)]];
[[expr evaluated for each iteration +1(end of loop)]]
)
The cases that are fastest on IE7 are those where the conditional expression in the for-loop is either missing or is simply comparing the values of 2 variables.
The long answer, without focussing on arr.length
, but keep in mind that here, you're getting a property of an object, that is, sort-of, inherited from the prototype.
The reason why is simply because of how Chrome's V8 compiles the code, and how the Object[[GetProperty]]
is implemented. Since JS arrays are just augmented objects (Array instanceof Object
is true
), getting a value from an array is, essentially the same as someObj.someProp
.
Most JS implementations use either a HashMap or HashTable for the objects. Chrome's V8 engine, is a bit of an odd one out, in a couple of crucial ways.
FF's SpiderMonkey/*Monkey engines compile JS code to intermediate byte-code, that runs on a virtual machine.
Their Rhino engine compiles JS to Java, which is also a VM environment. Cf the hybrid model in the img below
JS "engines" of old didn't even go that far, they were just parse-and-execute things. They did no or very little optimization or reflection on the code they were asked to parse.
V8 does things a bit different: it parses, optimizes and compiles the resulting AST (Abstract Syntax Tree) straight into machine-executable code. No byte-code virtual-machine stuff to hold you back:
So, Chrome's V8 compiles to machine code, which cuts down overall execution time (in most cases). In addition to that, the V8 engine does not use a HashTable for object properties. It creates classes:
To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes.
What does this mean for arr.length
:
//V8:
arr = ;//creates class, that has length property, value 0
arr.push(123);//arr points to class with property 0 = 123, length = 1
That means that, arr.length
or arr[0]
both are simple, atomic operations. In terms of time-complexity, they are as close as makes no difference both: O(1). Now, I'm not familiar with the internals of IE's JScript engine, but I'm prepared to take a punt on how arr.length
works:
arr.length;//->arr @instancelevel->search(length)
//
==>arr.prototype->search(length)
//
==> magic property, probably does something like:
return max(@instance.keys) +1
Now, this may range anywhere from pretty accurate to down-right absurd, but the principle stands: getting the length property from an array on engines that don't create classes for instances, is not atomic, and therefore slower.
Sadly, because of MS's software being closed source, I can't tell you what kind of AST the parser churns out, nor what the engine then does with that AST. You'll have to get friendly with someone working in Redmond, or send a very polite email, requesting more info (don't expect an answer, though :-P).
So, V8 compiles the AST directly to machine-executable code, and creates classes to speedup property. In theory, accessing a property in JS, running on V8 should be almost as fast as C++ code. In theory, that is :P.
Internet Explorer's JScript engine, especially IE7, is quite dated. It doesn't do optimization very well. It doesn't compile JS as well as modern day engines do.
I can't find the resource ATM, but I also seem to remember that IE's JScript implementation of objects was, in fact, rather lacking, too. I seem to recall it didn't even use a full-blown HashTable for its objects, which would explain why someArray.length
takes ages (since it requires a prototype lookup).
Read more here.
add a comment |
The short answer:
In your code the arr.length
is the major bottleneck. Simply because of the differences between the various implementations of JavaScript. Not only the implementations differ, but also what the engines actually do prior to executing your code.
Why do I think this: simple:
for([[expr evaluated at start of loop]];
[[expr re-evaluated on each iteration + 1(end of loop)]];
[[expr evaluated for each iteration +1(end of loop)]]
)
The cases that are fastest on IE7 are those where the conditional expression in the for-loop is either missing or is simply comparing the values of 2 variables.
The long answer, without focussing on arr.length
, but keep in mind that here, you're getting a property of an object, that is, sort-of, inherited from the prototype.
The reason why is simply because of how Chrome's V8 compiles the code, and how the Object[[GetProperty]]
is implemented. Since JS arrays are just augmented objects (Array instanceof Object
is true
), getting a value from an array is, essentially the same as someObj.someProp
.
Most JS implementations use either a HashMap or HashTable for the objects. Chrome's V8 engine, is a bit of an odd one out, in a couple of crucial ways.
FF's SpiderMonkey/*Monkey engines compile JS code to intermediate byte-code, that runs on a virtual machine.
Their Rhino engine compiles JS to Java, which is also a VM environment. Cf the hybrid model in the img below
JS "engines" of old didn't even go that far, they were just parse-and-execute things. They did no or very little optimization or reflection on the code they were asked to parse.
V8 does things a bit different: it parses, optimizes and compiles the resulting AST (Abstract Syntax Tree) straight into machine-executable code. No byte-code virtual-machine stuff to hold you back:
So, Chrome's V8 compiles to machine code, which cuts down overall execution time (in most cases). In addition to that, the V8 engine does not use a HashTable for object properties. It creates classes:
To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes.
What does this mean for arr.length
:
//V8:
arr = ;//creates class, that has length property, value 0
arr.push(123);//arr points to class with property 0 = 123, length = 1
That means that, arr.length
or arr[0]
both are simple, atomic operations. In terms of time-complexity, they are as close as makes no difference both: O(1). Now, I'm not familiar with the internals of IE's JScript engine, but I'm prepared to take a punt on how arr.length
works:
arr.length;//->arr @instancelevel->search(length)
//
==>arr.prototype->search(length)
//
==> magic property, probably does something like:
return max(@instance.keys) +1
Now, this may range anywhere from pretty accurate to down-right absurd, but the principle stands: getting the length property from an array on engines that don't create classes for instances, is not atomic, and therefore slower.
Sadly, because of MS's software being closed source, I can't tell you what kind of AST the parser churns out, nor what the engine then does with that AST. You'll have to get friendly with someone working in Redmond, or send a very polite email, requesting more info (don't expect an answer, though :-P).
So, V8 compiles the AST directly to machine-executable code, and creates classes to speedup property. In theory, accessing a property in JS, running on V8 should be almost as fast as C++ code. In theory, that is :P.
Internet Explorer's JScript engine, especially IE7, is quite dated. It doesn't do optimization very well. It doesn't compile JS as well as modern day engines do.
I can't find the resource ATM, but I also seem to remember that IE's JScript implementation of objects was, in fact, rather lacking, too. I seem to recall it didn't even use a full-blown HashTable for its objects, which would explain why someArray.length
takes ages (since it requires a prototype lookup).
Read more here.
The short answer:
In your code the arr.length
is the major bottleneck. Simply because of the differences between the various implementations of JavaScript. Not only the implementations differ, but also what the engines actually do prior to executing your code.
Why do I think this: simple:
for([[expr evaluated at start of loop]];
[[expr re-evaluated on each iteration + 1(end of loop)]];
[[expr evaluated for each iteration +1(end of loop)]]
)
The cases that are fastest on IE7 are those where the conditional expression in the for-loop is either missing or is simply comparing the values of 2 variables.
The long answer, without focussing on arr.length
, but keep in mind that here, you're getting a property of an object, that is, sort-of, inherited from the prototype.
The reason why is simply because of how Chrome's V8 compiles the code, and how the Object[[GetProperty]]
is implemented. Since JS arrays are just augmented objects (Array instanceof Object
is true
), getting a value from an array is, essentially the same as someObj.someProp
.
Most JS implementations use either a HashMap or HashTable for the objects. Chrome's V8 engine, is a bit of an odd one out, in a couple of crucial ways.
FF's SpiderMonkey/*Monkey engines compile JS code to intermediate byte-code, that runs on a virtual machine.
Their Rhino engine compiles JS to Java, which is also a VM environment. Cf the hybrid model in the img below
JS "engines" of old didn't even go that far, they were just parse-and-execute things. They did no or very little optimization or reflection on the code they were asked to parse.
V8 does things a bit different: it parses, optimizes and compiles the resulting AST (Abstract Syntax Tree) straight into machine-executable code. No byte-code virtual-machine stuff to hold you back:
So, Chrome's V8 compiles to machine code, which cuts down overall execution time (in most cases). In addition to that, the V8 engine does not use a HashTable for object properties. It creates classes:
To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes.
What does this mean for arr.length
:
//V8:
arr = ;//creates class, that has length property, value 0
arr.push(123);//arr points to class with property 0 = 123, length = 1
That means that, arr.length
or arr[0]
both are simple, atomic operations. In terms of time-complexity, they are as close as makes no difference both: O(1). Now, I'm not familiar with the internals of IE's JScript engine, but I'm prepared to take a punt on how arr.length
works:
arr.length;//->arr @instancelevel->search(length)
//
==>arr.prototype->search(length)
//
==> magic property, probably does something like:
return max(@instance.keys) +1
Now, this may range anywhere from pretty accurate to down-right absurd, but the principle stands: getting the length property from an array on engines that don't create classes for instances, is not atomic, and therefore slower.
Sadly, because of MS's software being closed source, I can't tell you what kind of AST the parser churns out, nor what the engine then does with that AST. You'll have to get friendly with someone working in Redmond, or send a very polite email, requesting more info (don't expect an answer, though :-P).
So, V8 compiles the AST directly to machine-executable code, and creates classes to speedup property. In theory, accessing a property in JS, running on V8 should be almost as fast as C++ code. In theory, that is :P.
Internet Explorer's JScript engine, especially IE7, is quite dated. It doesn't do optimization very well. It doesn't compile JS as well as modern day engines do.
I can't find the resource ATM, but I also seem to remember that IE's JScript implementation of objects was, in fact, rather lacking, too. I seem to recall it didn't even use a full-blown HashTable for its objects, which would explain why someArray.length
takes ages (since it requires a prototype lookup).
Read more here.
edited yesterday
Glorfindel
2761615
2761615
answered Oct 4 '13 at 8:59
Elias Van Ootegem
9,0232144
9,0232144
add a comment |
add a comment |
Since you asked this question here rather than on Stack Overflow, I'm going to propose this countdown iteration:
for (var y = arr.length - 1; y >= 0; --y) {
//do some maths
var el = arr[y];
el++;
}
The advantages are:
- You only calculate
arr.length
once, and do so without introducing a temporary variable - Each iteration, you compare
y
with zero. To compare with any other number, the CPU would first have to load both values into registers before executing the conditional branch instruction. To compare against zero, only the value ofy
needs to be loaded in a register; there is a special instruction for comparing against zero and conditionally branching.
That said, the performance gain by iterating backward instead of forward is negligible, and you should avoid the countdown technique if
- The processing of an element depends on the value of another element
- The processing of an element could fail — premature termination of the loop would be weird if the partial results are at the end of the array
add a comment |
Since you asked this question here rather than on Stack Overflow, I'm going to propose this countdown iteration:
for (var y = arr.length - 1; y >= 0; --y) {
//do some maths
var el = arr[y];
el++;
}
The advantages are:
- You only calculate
arr.length
once, and do so without introducing a temporary variable - Each iteration, you compare
y
with zero. To compare with any other number, the CPU would first have to load both values into registers before executing the conditional branch instruction. To compare against zero, only the value ofy
needs to be loaded in a register; there is a special instruction for comparing against zero and conditionally branching.
That said, the performance gain by iterating backward instead of forward is negligible, and you should avoid the countdown technique if
- The processing of an element depends on the value of another element
- The processing of an element could fail — premature termination of the loop would be weird if the partial results are at the end of the array
add a comment |
Since you asked this question here rather than on Stack Overflow, I'm going to propose this countdown iteration:
for (var y = arr.length - 1; y >= 0; --y) {
//do some maths
var el = arr[y];
el++;
}
The advantages are:
- You only calculate
arr.length
once, and do so without introducing a temporary variable - Each iteration, you compare
y
with zero. To compare with any other number, the CPU would first have to load both values into registers before executing the conditional branch instruction. To compare against zero, only the value ofy
needs to be loaded in a register; there is a special instruction for comparing against zero and conditionally branching.
That said, the performance gain by iterating backward instead of forward is negligible, and you should avoid the countdown technique if
- The processing of an element depends on the value of another element
- The processing of an element could fail — premature termination of the loop would be weird if the partial results are at the end of the array
Since you asked this question here rather than on Stack Overflow, I'm going to propose this countdown iteration:
for (var y = arr.length - 1; y >= 0; --y) {
//do some maths
var el = arr[y];
el++;
}
The advantages are:
- You only calculate
arr.length
once, and do so without introducing a temporary variable - Each iteration, you compare
y
with zero. To compare with any other number, the CPU would first have to load both values into registers before executing the conditional branch instruction. To compare against zero, only the value ofy
needs to be loaded in a register; there is a special instruction for comparing against zero and conditionally branching.
That said, the performance gain by iterating backward instead of forward is negligible, and you should avoid the countdown technique if
- The processing of an element depends on the value of another element
- The processing of an element could fail — premature termination of the loop would be weird if the partial results are at the end of the array
answered Oct 3 '13 at 17:42
200_success
128k15152413
128k15152413
add a comment |
add a comment |
To start with, it might be that IE7 is so slow, you can't really tell the differences with such small numbers. Another factor might be that "length" calculation is really slow on an array this size (well, back then ...) and that array access is "optimized" (at least better, and doesn't hurt much more than static property access).
But I think that IE7's just too slow for us to notice.
add a comment |
To start with, it might be that IE7 is so slow, you can't really tell the differences with such small numbers. Another factor might be that "length" calculation is really slow on an array this size (well, back then ...) and that array access is "optimized" (at least better, and doesn't hurt much more than static property access).
But I think that IE7's just too slow for us to notice.
add a comment |
To start with, it might be that IE7 is so slow, you can't really tell the differences with such small numbers. Another factor might be that "length" calculation is really slow on an array this size (well, back then ...) and that array access is "optimized" (at least better, and doesn't hurt much more than static property access).
But I think that IE7's just too slow for us to notice.
To start with, it might be that IE7 is so slow, you can't really tell the differences with such small numbers. Another factor might be that "length" calculation is really slow on an array this size (well, back then ...) and that array access is "optimized" (at least better, and doesn't hurt much more than static property access).
But I think that IE7's just too slow for us to notice.
answered Oct 3 '13 at 21:10
Ven
24626
24626
add a comment |
add a comment |
First of all, microbenchmarks like these don't really tell the whole story. It may only be "fast" or "slow" in this case. In real-world scenarios, it may tell another story (like when you have to deal with stuff other than just arrays).
Another thing is, with such small numbers in the IE tests... you can't really say it's fast :D
Another thing is (and most likely this would be the cause of the great divide in Chrome) is that modern JS compilers tend to optimize "hot code". Other forms of code are internally faster as well due to the browser's implementation of operations.
So in this case, case 2 and case 4 in Chrome might have been optimized internally, whereas case 3 might have been faster for IE7.
add a comment |
First of all, microbenchmarks like these don't really tell the whole story. It may only be "fast" or "slow" in this case. In real-world scenarios, it may tell another story (like when you have to deal with stuff other than just arrays).
Another thing is, with such small numbers in the IE tests... you can't really say it's fast :D
Another thing is (and most likely this would be the cause of the great divide in Chrome) is that modern JS compilers tend to optimize "hot code". Other forms of code are internally faster as well due to the browser's implementation of operations.
So in this case, case 2 and case 4 in Chrome might have been optimized internally, whereas case 3 might have been faster for IE7.
add a comment |
First of all, microbenchmarks like these don't really tell the whole story. It may only be "fast" or "slow" in this case. In real-world scenarios, it may tell another story (like when you have to deal with stuff other than just arrays).
Another thing is, with such small numbers in the IE tests... you can't really say it's fast :D
Another thing is (and most likely this would be the cause of the great divide in Chrome) is that modern JS compilers tend to optimize "hot code". Other forms of code are internally faster as well due to the browser's implementation of operations.
So in this case, case 2 and case 4 in Chrome might have been optimized internally, whereas case 3 might have been faster for IE7.
First of all, microbenchmarks like these don't really tell the whole story. It may only be "fast" or "slow" in this case. In real-world scenarios, it may tell another story (like when you have to deal with stuff other than just arrays).
Another thing is, with such small numbers in the IE tests... you can't really say it's fast :D
Another thing is (and most likely this would be the cause of the great divide in Chrome) is that modern JS compilers tend to optimize "hot code". Other forms of code are internally faster as well due to the browser's implementation of operations.
So in this case, case 2 and case 4 in Chrome might have been optimized internally, whereas case 3 might have been faster for IE7.
answered Oct 4 '13 at 1:56
Joseph
22.5k21835
22.5k21835
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f32186%2fwhy-is-this-code-so-much-faster-relatively-in-ie7%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
8
Not sure if this belongs to codereview.SE but it does look like a pretty interesting question.
– Josay
Oct 3 '13 at 15:20
@Josay, I debated for a while whether it was more suited to here or Stack Overflow, but settled for here in the end. Happy to have the question migrated if the mods feel it would be more suitable over at SE.
– Andy F
Oct 3 '13 at 15:22
Yeah, I'd wait for the mods to decide. However, this doesn't quite fit "understanding code snippets" because because you already know what's happening. You just want to know why.
– Jamal♦
Oct 3 '13 at 17:14
would be interesting to test also
for (var el, y = 0; el = arr[y]; y++) { el++; }
– Stuart
Oct 3 '13 at 19:29
1
@AndyF: A very interesting question, I must say. Sadly, I think programmers.stackexchange or (though borderline) even computerscience.stackexchange. Anyway, I've posted a (rather verbose) answer here anyway... ;P
– Elias Van Ootegem
Oct 4 '13 at 10:09