September 04, 2013

requestAnimationFrame is what you need for browser-based animations

Are you still using setInterval for animating things on your website?

Forget about it! This is what I discovered yesterday. I started to make a simple parallax scrolling and used setInterval initially. I was not much convinced with the result, because I encountered some flicker and minor slowdowns. So, I searched for hints for optimizing my experience and discovered there is some relatively new technique out there called requestAnimationFrame. Here is what I've done intially
function ParallaxScroller() {
    var that = this;    
    var layers = [];
            
    this.addLayer = function(layer){
        layers.push(layer);    
    }
    
    
    this.start(timeout){
        setInterval(render, timeout);
    }
    
    this.render=function(){        
        for(var i=0; i<layers.length; ++i){
            layers[i].update();
        }        
    }
};

var scroller = new ParallaxScroller();
scroller.addLayer( /* layer */ );
scroller.start(50);
And here is the same code using requestAnimationFrame
function ParallaxScroller() {
    var that = this;    
    var layers = [];
            
    this.addLayer = function(layer){
        layers.push(layer);    
    }
        
    this.render=function(){        
        for(var i=0; i<layers.length; ++i){
            layers[i].update();
        }                
        requestAnimationFrame(that.render); // # HERE!
    }
};

var scroller = new ParallaxScroller();
scroller.addLayer( /* layer */ );
scroller.render();
The thoughtful reader may have noticed, that there is no interval passed to requestAnimationFrame. To understand what is happening here, it is vital to know about the essential difference between requestAnimationFrame and setInterval:

Using setInterval for animations forces the browser to refresh the screen when the related callback is triggered. That means, screen updates occur at any time, and have a good chance to be unnecessary. As a result the animations can be crude. Using rFA instead overcomes those "update interruptions". As the name says it requests an update frame. So, the browser becomes responsible to decide whether a callback is triggered, or not. Yes, he might decide not to trigger, for example if the updating page is not visible. The browser can synchronize the callback with its own refreshing rate, which is usually 60Hz, to avoid unnecessary (and CPU costly) repaints. Consequently, you get smoother results due to synchronized refreshes and can safe CPU resource (and battery life), especially while the screen is not visible.

That's why I simply do not care about frame rates when animate my stuff on the screen using rFA. The animations are updated in the correct time slot nearly all 16 ms. There are other articles out in the wild which explain more precisely how it works, like "Better performance with requestAnimationFrame", CreativeJS requestAnimationFrame , and "Better JavaScript animations with requestAnimationFrame". Also interesting is "Microsoft's rFA Testdrive", that compares both methods visually.

No comments:

Post a Comment