0

A little background: I'm currently working on a project that contains about 20-30 items with linear gradients which animate their stops continuously throughout the entire run time of the experience.

gradient docs animate docs

As the site runs, the framerate drops continuously over time. Running the chrome dev tools timeline shows an insane amount of requestAnimationFrame calls from this library; more and more over time, thus the consistent drop in framerate. So much so that the chrome dev tools buffer fills up in a few seconds.

screen shot 2015-01-29 at 12 49 40 am

Video

Here is my code:

var colors;
var fnAnimate;
var gradient;
var s1;
var s2;
var s3;
var stops;

colors = ['#EFFF22', '#D1FBFF', '#2759FF'];

gradient = draw.gradient('linear', function(stop) {
    s1 = stop.at(0, colors[0]);
    s2 = stop.at(0.4, colors[1]);
    s3 = stop.at(1, colors[2]);
    stops = [s1, s2, s3];
});

fnAnimate = function() {
    var color;
    var stop;

    color = _.sample(colors);
    stop = _.sample(stops);
    stop.animate().update({
        color: color
    });
};

setInterval(function() {
    fnAnimate();
}, 1000);

From my understanding of the documentation, each invocation of animate on an object should stop any preexisting animation on said object. Checking here in the source, that does seem to be the case. If you look closer at the stop method, it looks to clear an animation timeout and delete/reset some properties. It is not doing, however, one vital thing.

Looking through the fx.render method, on lines 189 and 192, we enter a requestAnimationFrame loop. This is good. BUT after looking around this entire library, cancelAnimationFrame is nowhere to be found. There's also an absence of a shim for it in the helpers.js next to the requestAnimationFrame shim.

Essentially what is happening is that every time animate is called, a requestAnimationFrame loop is created, but never killed, nor a reference to it stored; thus creating zombie animation loops. This would explain the extreme amount of requestAnimationFrame calls I'm seeing in my dev tools timeline.

Zach
  • 21
  • 4
  • requestAnimationFrame might better be called `requestOneSingleAnimationFrame`. 'requestAnimationFrame(animateMe)' will request that the browser call animateMe **exactly one time--not repeatedly** like setInterval. And rAF will die after its one call to animateMe is achieved. That's why you see so many executions of rAF--because rAF must be called every time you want to request a new animation frame. In practice, a new rAF is usually called within the animateMe function that was triggered by the last (now dead) rAF. – markE Jan 29 '15 at 18:08
  • You are correct. However, if you look here https://github.com/wout/svg.js/blob/master/src/fx.js#L189, you'll see that the render function calls itself, thus creating a loop. – Zach Jan 29 '15 at 22:27
  • Sure, that's the normal pattern for using rAF---rAF calls a function that contains the next rAF call. – markE Jan 29 '15 at 22:31
  • So if you take a look at the stop function https://github.com/wout/svg.js/blob/master/src/fx.js#L368, there's nothing that cancels that loop. – Zach Jan 29 '15 at 23:57
  • I can't really review the entire svgjs library with you, but the stop() function calls `this.animate(0)` which sets the variable `d` to zero which eventually sets `start` equal to `finish` which terminates the animation. BTW, it's not unusual to let an rAF loop run forever. As long as the loop does no work it's relatively harmless. – markE Jan 30 '15 at 05:27
  • closed with https://github.com/wout/svg.js/commit/2fc54cb89bef303efa9be3dfcd26ff10921deb04 – Fuzzyma Feb 14 '16 at 10:12

0 Answers0