RequestAnimationFrame is a function in javascript which is used to create animations directly in the browser. Javascript has been used for doing animations for a long time, and it's pretty awesome what things really can be done with the language. For simpler stuff though as animated hover effects when someone hovers their mouse cursor over some button or link, or for example for simpler drop down menus, it's usually enough with just css.

But for doing more advanced animations, javascript is usually required. In the past timeouts and intervals with the functions setTimeout and setInterval have been used for doing this. And it's always been possible to get alright animations with them, but it's not very optimal and it's really hard to get them feeling "smooth".

Different web browsers also have their own ways of doing things and have different "timer resolutions". That means animations speed will be a little different in every browser, which has led to lots of frustration, especially when it comes to making games. Also there's problems like if too much is happening in the intervals the processor can get "throttled" or "spiked", leading to very bad lag. Don't misunderstand, setTimeout and setInterval are really great functions, just not so great for animations.

So something had to be done to solve these problems, and the answer was the function requestAnimationFrame. An optimized and standardized way of doing animations in browsers, and which works really great. RequestAnimationFrame both has good performance, is energy effective (doesn't waste too much of mobile devices batteries among other things), is optimized for animations, turns itself off when users are changing tabs, and is very easy to use. Another good thing is it's supported by almost all browsers.

Difference between timers and requestAnimationFrame

In the past when setInterval was used for animations the code could perhaps look like in the example below. Instead of a normal loop like for or while setInterval is a recursive function which calls itself over and over again, after the time in milliseconds has passed, set as its second argument.

var p = document.querySelector('p');
var i = 0;

setInterval(function () {
p.textContent = i++;
}, 30);

RequestAnimationFrame works in a similar way. It takes one argument which is the function it should call (can be an anonymous function just like above). There's no argument for setting its execution delay or fps. RequestAnimationFrame sets this automatically based on the environment, and tries to achieve 60 fps. It gets as close as possible, so we don't even have to worry about it.

var p = document.querySelector('p');
var i = 0;

function count () {
p.textContent = i++;
requestAnimationFrame(count);
}
count();

0

To stop or pause animations requestAnimationFrame first has to be assigned to a variable like in the example below. Then it can be stopped by using the variable as argument to the function cancelAnimationFrame.

var req;

function animate () {
req = requestAnimationFrame(animate);
}
animate();

document.querySelector('#stop').onclick = function () {
cancelAnimationFrame(req);
};

RequestAnimationFrame in practice

As of today when this is written no browser prefixes are required for requestAnimationFrame like -webkit- or -moz- etc. All browsers that supports the function (all except ie9 and less) already have it implemented in the standardized way which is really nice.

If ie9 and less have to be supported then unfortunately requestAnimationFrame can't be used. Then the only option is to "fall back" to the old setTimeout or setInterval functions.

Below is a little example on how requestAnimationFrame can be used to animate the background color on a website (this site that is). It's just one small thing the function can be used for. The possibilities are endless so to say, and in all game programming going on with html5 we're probably going to see lots of it in the future.

var main = document.querySelector('#main');
var count = 0;
var req;

function changeBackgroundColor () {
main.style.background = 'hsl(' + count + ', 50%, 50%)';

if (++count > 360) {
count = 0;
}
req = requestAnimationFrame(changeBackgroundColor);
}

document.querySelector('#stop').onclick = function () {
if (this.value === 'Test') {
this.value = 'Stop';
changeBackgroundColor();

} else {
this.value = 'Test';
cancelAnimationFrame(req);
}
};