Using setInterval with requestAnimationFrame
Asked Answered
G

1

6

I'd like to use setInterval for actual steps in a program and requestAnimationFrame for rendering. I was under the impression this would be the perfect mix: rendering speed would not slow down actual progression, so dips in frame rate would only affect frame rate and still sync up. What I got, however, were drops in the setInterval function as well.

An example of what I mean, intentionally bogged down with shadows: http://jsfiddle.net/Ltdz168m/

Reduce or increase the number of refills and you'll see the difference

It would appear that requestAnimationFrame is actually not a solution to rendering lag slowing down JavaScript. How then would I update the logic side of things, which can be done at 60 fps, without hindrance from rendering? Are WebWorkers absolutely necessary?

Genny answered 16/9, 2014 at 22:32 Comment(0)
C
17

The problem is that the browser is still only capable of doing one thing at a time. So, if it's rendering, it can't update the position.

When doing stuff to support variable framerates, you should always use Delta Timing. It works something like this:

requestAnimationFrame(function(e) {
  document.getElementById('status').innerHTML = "Delta time: "+e;
  
  // lag randomly
  while(Math.random() > 0.0000001) {}
  
  requestAnimationFrame(arguments.callee);
});
<div id="status"></div>

As you can see (hopefully), regardless of framerate, the delta time shown goes up consistently. This means you can do, for example, angleFromStart = e/1000*Math.PI*2; and your dot will orbit at precisely 60 RPM.

var angle=0,
    radian=Math.PI/180;
var canvas=document.getElementById("canvas"),
    context=canvas.getContext("2d");
context.shadowColor="black";
context.shadowBlur=100;
requestAnimationFrame(function draw(e) {
  angle = e/1000*Math.PI*2;
    var x=canvas.width/2+Math.cos(angle)*canvas.width/4,
        y=canvas.height/2+Math.sin(angle)*canvas.height/4;
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.beginPath();
    context.arc(x, y, 5, 0, Math.PI*2);
    context.closePath();
    for(var i=0; i<255; i++) {
        context.fill();
    }
    requestAnimationFrame(draw);
});
#canvas {
    border: 1px solid black;
}
<canvas id="canvas"></canvas>

PS: I love the new Stack Snippet feature!

Chapbook answered 16/9, 2014 at 22:54 Comment(4)
I thought of this but boy would it be a lot of work. I suppose it's necessary work, though. And I have to agree, that is a neat feature; beats jsfiddle links.Genny
It's actually less code to use Delta Timing than it is to use setInterval ;)Chapbook
Well I just had a loop set up with a .update() on everything, so I'll need to start passing it through that and applying to quite a bit of math work (far more than that example). Still, it should pay off to sync things up.Genny
+1 for the good answer. But a Beer for having the first use of Stack Snippets I've seen!Moke

© 2022 - 2024 — McMap. All rights reserved.