Update (2011/07/09)
Firefox 5 implements mozRequestAnimationFrame but not mozCancelRequestAnimationFrame. To ensure the shims work as expected the code has been tweaked to force Firefox to use setTimeout/setInterval until mozCancelRequestAnimationFrame is available. Download from Gist
Update (2011/06/04)
Modified the functions so that they can be cancelled with drop in replace functions for clearTimeout() & clearInterval(). The modifications are up on Gist. Thanks to Luke Wilson for the suggestion!
The CSS Animations keyframe events shim that I recently posted makes use of a new experimental Javascript function requestAnimationFrame(). This function is designed to produce much higher performance than the traditional alternatives setTimeout() or setInterval().
This is because browser developers have worked hard to enable acurate 60fps performance from requestAnimationFrame(), Paul Irish explains it best on his blog:
The browser can optimize concurrent animations together into a single reflow and repaint cycle, leading to higher fidelity animation. For example, JS-based animations synchronized with CSS transitions.
This is great but you often want to receive callbacks at frequencies other that 60fps, especially when you’re using timing functions for something other than animation. Both setTimeout() and setInterval() allow for an arbitrary time in milliseconds to be provided, e.g.
setTimeout(function(){ alert("hello world") }, 1000)
The above would delay the function call by 1000 milliseconds (1 second).
So we want the performance gains of requestAnimationFrame() but the flexibility, familiarity and ease of use of setTimeOut() & setInterval().
This can be easily achieved using a couple of shim functions that I’ve called requestTimeout() and requestInterval() which I’ve outlined below. They are also available on Gist if you prefer.
requestTimeout(fn, delay) Fork on Gist →
window.requestTimeout = function(fn, delay) {
if( !window.requestAnimationFrame &&
!window.webkitRequestAnimationFrame &&
!window.mozRequestAnimationFrame &&
!window.oRequestAnimationFrame &&
!window.msRequestAnimationFrame)
return window.setTimeout(fn, delay);
var start = new Date().getTime(),
handle = new Object();
function loop(){
var current = new Date().getTime(),
delta = current - start;
delta >= delay ? fn.call() : handle.value = requestAnimFrame(loop);
};
handle.value = requestAnimFrame(loop);
return handle;
};
window.clearRequestTimeout = function(handle) {
window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) :
window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) :
window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) :
window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) :
window.msCancelRequestAnimationFrame ? msCancelRequestAnimationFrame(handle.value) :
clearTimeout(handle);
};
requestInterval(fn, delay) Fork on Gist →
window.requestInterval = function(fn, delay) {
if( !window.requestAnimationFrame &&
!window.webkitRequestAnimationFrame &&
!window.mozRequestAnimationFrame &&
!window.oRequestAnimationFrame &&
!window.msRequestAnimationFrame)
return window.setInterval(fn, delay);
var start = new Date().getTime(),
handle = new Object();
function loop() {
var current = new Date().getTime(),
delta = current - start;
if(delta >= delay) {
fn.call();
start = new Date().getTime();
}
handle.value = requestAnimFrame(loop);
};
handle.value = requestAnimFrame(loop);
return handle;
}
window.clearRequestInterval = function(handle) {
window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) :
window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) :
window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) :
window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) :
window.msCancelRequestAnimationFrame ? msCancelRequestAnimationFrame(handle.value) :
clearInterval(handle);
};
Both of these functions require Paul Irish’s requestAnimFrame() shim which can be found on his blog. If a high performance function isn’t found then both functions will fall back to the native counterparts instead of making use of Paul’s shim.

Pingback: requestAnimationFrame for smart animating « Paul Irish
Pingback: La boucle principale avec requestAnimationFrame
Pingback: HTML5 Canvas Performance and Optimization Tips, Tricks and Coding Best Practices | Build Future Repository