3000ms で、800pixcel を水平移動する。その2か3

正直なところ遅延など多くないだろうと高をくくっていた。
setInterval よりも setTimeout の遅延があるどろうとおもい、それで実験。
そして遅延は、思いのほか大きい。
必要なパラメータは、把握した。

<!DOCTYPE html>
<title>遅延時間を考えて移動する</title>
<meta charset="UTF-8">
<style>
#invader {
  list-style : none;
  position: absolute;
  margin : 0;
  padding: 0;
  top : 0px;
  left: 3px;
}

#invader li {
  margin : 0;
  padding : 0;
  display : none;
}


</style>


<ol id ="invader">
  <li class="type1 v">
    <img id ="inv3"
         alt="インベーダ"
         src="data:image/gif;base64,
              R0lGODlhMAAYAIAAAP8ntf///yH5BAEAAAEALAAAAAAwABgAAAJijI95wO2sopzqWUCzXtft
              34Vi8yHjeZUcymJgC3tZTLtUHWth9fDp3PGREjvgz9QjBo04lK7JekJPKkMReaxiLcKkdutd
              cb+BMdgmhlTNabQ1/JKdu24VW3L/5unkOVNNUQAAOw==">
  <li class="type2">
    <img id="inv3o"
         alt="インベーダ"
         src="data:image/gif;base64,
              R0lGODlhMAAYAIAAAP8ntf///yH5BAEAAAEALAAAAAAwABgAAAJmjI95wO2sopzqWUCzXtft
              34Vi8yHjeZUcymJgC3tZTLtUHWth9fDp3PGREjvgz9QjBo04lK7JekJPKqUMea3ektihdps1
              WL6SMRNCXnkn5nSgzeaW4NZ1HQ22d/FCfll+Z9MnaFAAADs=">
</ol>

<canvas id="hoge" width="800" height="200"></canvas>
<p>遅延時間:<input type="text" value="0" id="fuga"></p>


<script>

var changePattern =
  (function () {
    
    var pattern = document.querySelectorAll ('#invader > li');
    var state = 0;
    var max = 2;
    
    Array.prototype.forEach.call (
      pattern,
      function (e) {
        e.style.display = 'none';
      }
    );
    
    function change () {
      pattern[state].style.display = 'none';
      state = (state + 1) % max;
      pattern[state].style.display = 'inline';
    }
    
    change ();
    
    return change;

  }) ();

setInterval (changePattern, 200);


var moveInvader =
  (function (time, distance, interval) {
    var style = document.querySelector ('#invader').style;
    var x = 0;
    var y = 30;
    
    var max_jump = 3; //遅延があった場合の最大間引き回数
    var step = (distance / time) * interval; //移動量
    var err = 0; //1回の移動ででる端数移動量
    var count = 0; // コールバックされた回数(遅延時間を計算するため)
    var startTime = null; //スタート時間(遅延時間を計算するため)
    
    
    // 移動する
    function move (timeStamp) {
      var mv = step + err; // 端数も含める
      var ix = Math.floor (mv); // 移動量(整数)
      var jump; // 遅延が発生した場合に飛び越す回数
      var delay = (timeStamp - startTime) - interval * count; //遅延時間の計算

      // 遅延がある場合
      if (0 < delay) {
        jump = Math.floor (delay / interval); //何回分のコールバックが不足していたか
        if (max_jump < jump) {//遅延が大きすぎる場合、抑制する
          jump = max_jump;
        }
        count += jump; //コールバックを間引きしたことにする
        err += jump * step; //誤差に含めてしまう
      }
      document.getElementById('fuga').value = delay;

      err = mv % 1;
      x += ix;
      count++;
      return (distance < x) ? true: setPosition ();
    }
    
    function setPosition () {
      style.left = x + 'px';
      style.top = y + 'px';
    }
    
    function loop () {
      var timeStamp = (new Date).getTime ();

      if (! move (timeStamp))
        setTimeout (loop, interval);
    }
    
    setPosition ();
    startTime = (new Date).getTime ();
    loop ();

  }) (3000, 800, 10);



</script>