0

im creating a HTML5 Canvas animations and wish to reduce / throttle the frame rate. I'm currently using the requestAnimationFrame method. To throttle the frame rate, I use setTimeout.

Is there a better / more efficient way to do this?

// Game - animation loop 
      var fps = 5;
      function step() {
        setTimeout(function() {
          update();
          draw();
          window.requestAnimationFrame(step);
        }, 1000 / fps);
      }

Thanks

stckpete
  • 571
  • 1
  • 4
  • 13
  • I think this answer can explain it to you http://stackoverflow.com/a/19772220/2542172 – Rudolf Manusachi Jun 11 '16 at 09:08
  • `requestAnimationFrame` now automatically sends in a timestamp that you can use to throttle execution of your code. See this [Q&A](http://stackoverflow.com/questions/19000109/javascript-cant-adjust-framerate-requestanimationframe/19008984#19008984). :-) – markE Jun 11 '16 at 18:14

1 Answers1

0
const fps = 5;
const delay = Math.ceil(1000 / fps);
let last = Date.now();
let now;

function step () {
    now = Date.now();
    if(now - last < delay) {
        return requestAnimationFrame(step);
    }
    last = now;
    update();
    draw();
    requestAnimationFrame(step);
}

step();
Azamantes
  • 1,435
  • 10
  • 15
  • thanks azamantes and Rudolf.. @ azamantes, I assume this will work if I replace const and let with 'var'? – stckpete Jun 11 '16 at 09:19
  • Absolutely, `const` and `let` are ES6 syntax, you can very well replace them with old good `var`. In this particular case I don't think their behaviour would be different from intended. – Azamantes Jun 11 '16 at 09:20
  • 2
    I will point out that the callback passed to `requestAnimationFrame` is called with one argument that contains a high precision time stamp with the time in ms since page load. So there is no need for the `Date.now()` call. Should have `function step( time )` this will give time to 1/1,000,000th second precision and avoid the frame skip you can get with 1/1000th Date timer. – Blindman67 Jun 12 '16 at 08:12
  • Yes and you would get `InternalError: too much recursion ` because of calling the same function recursively and blocking the whole page with your 1/10000000...th second precision. `requestAnimationFrame` gives the browser the time to do other things in between the lonely 5 frames per second :) You should never call your function recursively infinitely because computers are so fast you will just get an error. And for us humans those 16ms difference delay (in the worst case) really won't make any difference. And it's the worst case. – Azamantes Jun 12 '16 at 09:19
  • Azamantes Your comment to @Blindman67 is not correct. `requestAnimationFrame` self-throttles its execution to the display refresh speed (usually 60 times per second) so you will never have a "runaway" rAF. And rAF is pseudo-asynchronous in that it permits all non-rAF activity between rAF callbacks. Also, IME, modern browsers have optimized rAF looping so that any particular rAF callback that does nothing (because they are waiting your desired delay time), have very little impact on performance. – markE Jun 12 '16 at 17:38
  • I misunderstood his post (I had just woken up :)). Obviously he's correct. You would simply have to manage the FPS via some sort of counter. – Azamantes Jun 12 '16 at 17:51