Saturday, 31 August 2019

RequestAnimationFrame speeds up/slows down periodically

From my understanding, requestAnimationFrame should run as close as possible to the browser's frame rate, which is approximately 60fps. To ensure that this is indeed taking place, I have been logging timestamps for each requestAnimationFrame invocation like so:

function animate(now){
    console.log(now);
    window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate);

Console.log data shows that invocations are consistently taking place approximately 0.016674 milliseconds apart, thus indicating that the frame rate is ≈ 60fps (59.9736116108912fps to be exact).

Console.logs (sample data):

Timestamp   FPS               (Current - previous) timestamp
------------------------------------------------------------
100.226     59.97361161       0.016674
116.9       59.97361161       0.016674
133.574     59.97361161       0.016674
   .             .               .
   .             .               .
150.248     59.97361161       0.016674
166.922     59.97361161       0.016674
183.596     59.97361161       0.016674
200.27      59.97361161       0.016674

Up to this point, requestAnimationFrame invocations are occurring at consistent time intervals, and no invocation lags behind/executes too fast.

However, modifying the contents of the animate() function to execute a relatively more complex function, results in requestAnimationFrame invocations which are not as consistent.

Console.logs (sample data):

Timestamp       FPS               (Current - previous) timestamp
------------------------------------------------------------
7042.73         59.97361161       0.016674
7066.278        42.4664515        0.023548
7082.952        59.97361161       0.016674
7099.626        59.97361161       0.016674
   .                 .                .
   .                 .                .
17104.026       59.97361161       0.016674
17112.84        113.4558657       0.008814
17129.514       59.97361161       0.016674
17146.188       59.97361161       0.016674

As can be seen in the above data sample, timestamp differences and frame rates are no longer steady, and sometimes occur too soon/too late, resulting in inconsistent frame rates. Had requestAnimationFrame been consistently invoked late, I would have assumed that due to JavaScript's single-threaded nature, complex code residing in the animate() function is taking too long to execute, and thus results in a delayed requestAnimationFrame invocation. However, since requestAnimationFrame is occasionally being invoked too early, this does not seem to be the case.

My code (skeleton):

for (var counter = 0; counter < elements.length; counter ++) //10 elements
{
  //some other code

  animate(element);
}

function animate(element)
{
   // function invocation => performs some complex calculations and animates the element passed in as a parameter

   window.requestAnimationFrame(function() { animate(element) } );
}

As can be seen in the above code snippet, requestAnimationFrame is being invoked multiple times for each element, within the initial for loop. RequestAnimationFrame invocations are also intended to go on infinitely, for each of the elements. Since the animation to be performed is highly time-critical (animation timing is very important in this scenario and should be as accurate as possible), it is essential that requestAnimationFrame invocations occur at consistent time intervals throughout. These time intervals should ideally be as close as possible to 0.016674 (≈ 60fps).

  1. Would you be able to clarify what is causing this inconsistent requestAnimationFrame behaviour?

  2. Can any optimisations be applied to ensure that requestAnimationFrame invocations are executed at consistent time intervals?

  3. Can better timing accuracy be achieved if I use some other kind of functionality (say, web workers in combination with the setInterval() function)?



from RequestAnimationFrame speeds up/slows down periodically

No comments:

Post a Comment