title: Poor JS/jQuery performance, particularly in IE9 and Firefox
body: <p>I'm having serious visual &amp; performance issues with the script below. The biggest problem is that the animation of the object is becoming really jerky, almost cripplingly so in IE9, but increasingly annoying in Firefox. </p>
  
  <p>It has been pretty fast until recently - but I'm concerned the complexity is slowing things down. Oddly the <a href="http://www.webkit.org/perf/sunspider/sunspider.html" rel="noreferrer">Sunspider benchmark</a> runs faster in my IE9 instance, than in Firefox.</p>
  
  <p>The script (which is a snippet of a larger collection ***):</p>
  
  <ol>
  <li>Checks a HTML5 session storage log of the users progression through
  the game. </li>
  <li>Depending on the stage, animates an object between two
  points using <a href="https://github.com/MmmCurry/jquery.crSpline" rel="noreferrer">crSpline</a>. </li>
  <li>Ensures the browser window follows the object
  across a large canvas, via scrollLeft etc. </li>
  <li>Finally, it loads a popup window via <a href="http://www.jacklmoore.com/colorbox" rel="noreferrer">colorbox</a>. </li>
  <li>When this box is closed, the user progression log is incremented accordingly and the object moves again.</li>
  </ol>
  
  <p>Are there aby obvious speed improvments I could make to my code? There's a fair bit of repition, how can I reduce that? Are there any infinite loops running that I'm missing? Is there software I can use to profile slow points of the JS?</p>
  
  <p>*** (I can't provide the other JS files or HTML, but I have identified this script as the problem)</p>
  
  <hr>
  
  <p><strong>UPDATE:</strong>
  After a fair bit more testing, it appears that the step animate function - which follows the object in the window via scrollLeft - is causing the jerky animation. Removing it improves things considerably.</p>
  
  <p>This isn't a viable long term solution however. A quick fix is to call the follow function on complete, but this is a much less smooth experience for the end user, especially when the object moves longer distances.</p>
  
  <p><strong>So, how would I modify the step function to run a lot 'slower'/more efficiently?</strong> I'm guessing the jerkiness is caused by it using all the available resources to follow the object every millisecond.</p>
  
  <pre><code>(function ($) {
  
    sessionStorage.gameMainStage = 0 
  
    moveShip =  function() {
  
      switch (sessionStorage.gameMainStage)
  
  {
    case '1':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[715, 425], [582, 524], [556, 646], [722, 688], [963, 629], [1143, 467]]) },{
        duration: 10000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
            },
            complete: function() {
              $.colorbox({href:"dialog-1.html", width:"737px", height:"474px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
        }
      );
      break;
  
    case '2':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[1143, 467], [1343, 667], [1443, 367],  [1243, 167], [1499, 285]]) },
          {
            duration: 5000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
            },
            complete: function() {
              $.colorbox({href:"dialog-2", width:"737px", height:"547px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
  
          }
      );
      break;
  
    case '3':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[1499, 285], [1922, 423]]) },
          {
            duration: 5000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
            },
            complete: function() {
              $.colorbox({href:"dialog-3.html", width:"737px", height:"547px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
  
          }
      );
      break;  
  
    case '4':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[1922, 423], [2216, 578]]) },{
          duration: 5000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
              }, 
  
            complete: function() {
              $.colorbox({href:"game-1.html", width:"737px", height:"547px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
          }
      );
      break;
  
    case '5':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[2216, 578], [2769, 904]]) },{
        duration: 5000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
            }, 
  
            complete: function() {
              $.colorbox({href:"dialog-4.html", width:"737px", height:"547px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
        }
      );
      break;
  
    case '6':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[2769, 904], [3263, 903]]) },{
        duration: 5000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
            }, 
  
            complete: function() {
              $.colorbox({href:"dialog-5.html", width:"737px", height:"547px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
        }
      );
      break;
  
    case '7':
      $.colorbox({href:"game-2.html", width:"500px", height:"600px", iframe: true, overlayClose: false, escKey: false, close: ""});
    break;
  
    case '8':
      $.colorbox({href:"dialog-6.html", width:"737px", height:"567px", iframe: true, overlayClose: false, escKey: false, close: ""});
    break;
  
    case '9':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[3263, 903], [4141, 820]]) },{
        duration: 5000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
            }, 
  
            complete: function() {
              $.colorbox({href:"dialog-7.html", width:"737px", height:"547px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
        }
      );
      break;
  
    case '10':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[4141, 820], [4568, 949], [4447, 1175]]) },{
        duration: 5000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
            }, 
  
            complete: function() {
              $.colorbox({href:"dialog-8.html", width:"737px", height:"434px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
        }
      );
      break;
  
    case '11':
      $.colorbox({href:"dialog-9.html", width:"737px", height:"567px", iframe: true, overlayClose: false, escKey: false, close: ""});
    break;
  
    case '12':
      $("#object").animate(
        { crSpline: $.crSpline.buildSequence([[4447, 1175], [4701, 1124], [4816, 822]]) },{
        duration: 5000,
            step: function() {
              var mover = $('#object'),               
              posX = mover.position().left;
              posY = mover.position().top;
  
              $(window)
              .scrollLeft(posX - $(window).width() / 2)
              .scrollTop(posY - $(window).height() / 2);
            }, 
  
            complete: function() {
              $.colorbox({href:"dialog-10.html", width:"900px", height:"687px", iframe: true, overlayClose: false, escKey: false, close: ""});
            }
        }
      );
      break;
  }
  
  };
  
  })(jQuery);
  </code></pre>