Why is this code so much faster (relatively) in IE7?












11














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 in Chrome



Test results in IE7
enter image description here



Here are the jsperf tests if you want to run them yourselves.



Why is the second code snippet faster than the rest in IE7?










share|improve this question




















  • 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
















11














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 in Chrome



Test results in IE7
enter image description here



Here are the jsperf tests if you want to run them yourselves.



Why is the second code snippet faster than the rest in IE7?










share|improve this question




















  • 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














11












11








11







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 in Chrome



Test results in IE7
enter image description here



Here are the jsperf tests if you want to run them yourselves.



Why is the second code snippet faster than the rest in IE7?










share|improve this question















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 in Chrome



Test results in IE7
enter image description here



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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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














  • 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








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










4 Answers
4






active

oldest

votes


















11














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:



JS engines compilation models



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.






share|improve this answer































    3














    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 of y 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






    share|improve this answer





























      0














      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.






      share|improve this answer





























        0














        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.






        share|improve this answer





















          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
          });


          }
          });














          draft saved

          draft discarded


















          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









          11














          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:



          JS engines compilation models



          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.






          share|improve this answer




























            11














            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:



            JS engines compilation models



            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.






            share|improve this answer


























              11












              11








              11






              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:



              JS engines compilation models



              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.






              share|improve this answer














              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:



              JS engines compilation models



              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.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited yesterday









              Glorfindel

              2761615




              2761615










              answered Oct 4 '13 at 8:59









              Elias Van Ootegem

              9,0232144




              9,0232144

























                  3














                  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 of y 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






                  share|improve this answer


























                    3














                    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 of y 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






                    share|improve this answer
























                      3












                      3








                      3






                      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 of y 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






                      share|improve this answer












                      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 of y 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







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Oct 3 '13 at 17:42









                      200_success

                      128k15152413




                      128k15152413























                          0














                          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.






                          share|improve this answer


























                            0














                            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.






                            share|improve this answer
























                              0












                              0








                              0






                              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.






                              share|improve this answer












                              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.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Oct 3 '13 at 21:10









                              Ven

                              24626




                              24626























                                  0














                                  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.






                                  share|improve this answer


























                                    0














                                    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.






                                    share|improve this answer
























                                      0












                                      0








                                      0






                                      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.






                                      share|improve this answer












                                      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.







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Oct 4 '13 at 1:56









                                      Joseph

                                      22.5k21835




                                      22.5k21835






























                                          draft saved

                                          draft discarded




















































                                          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.




                                          draft saved


                                          draft discarded














                                          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





















































                                          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







                                          Popular posts from this blog

                                          How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

                                          is 'sed' thread safe

                                          How to make a Squid Proxy server?