Um grande passo pra evolução do HTML não precisar de plugins como Flash e Silverlight pra renderizar conteúdo e fazer animações ou jogos é a implementação de um controle de frames (além da aceleração por hardware que hoje já está presente em algumas features do CSS3).
Quando se fala em jogos e animações, pensamos em quantidade de frames por segundo, ou seja, quantas vezes por segundo algo vai mexer na tela.
Uma quantidade razoável pro trabalho não ficar “pesado” ou “travado” é cerca de 30 frames por segundo. Enquanto o máximo que o olho humano consegue distinguir é em torno de 60 frames por segundo, ou seja, não adianta fazer uma animação com intervalo de 10 milisegundos, seu olho não vai enxergar isso.
Antes, pra fazermos uma animação, trabalhávamos com o setInterval fixo de X milisegundos, ou então, criavamos e chamavamos uma função que se auto-invocava novamente com setTimeout também com um valor fixo de X milisegundos. O problema é que esse X de milisegundos varia de acordo com cada browser, cada processador e alguma hora acabava ficando ou muito lento, ou muito rápido.
Hoje, é possível trabalhar com o requestAnimationFrame, e ao invés de você gerenciar intervalo para o processamento, o browser faz isso.
Imaginem uma função onde algo, sei lá, um boneco, ande.
Como seria com setTimeout?
funcion mover(){
var boneco = document.getElementById('boneco');
boneco.style.left = (parseInt(boneco.style.left.replace('px','')) + 2).toString() + 'px';
}
setInterval(mover,20); // reinvoca a cada 20 miliseg.
Já com requestAnimationFrame seria assim:
funcion mover(){
var boneco = document.getElementById('boneco');
boneco.style.left = (parseInt(boneco.style.left.replace('px','')) + 2).toString() + 'px';
mozRequestAnimationFrame(mover);
}
mover();
Nesse caso funcionaria só pra Firefox, mas tem uma função já que funciona cross-browser e pra usuários de browsers sem HTML5 tem um work-around com setTimeout:
window.animationFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
Nesse caso, ficaria assim:
funcion mover(){
var boneco = document.getElementById('boneco');
boneco.style.left = (parseInt(boneco.style.left.replace('px','')) + 2).toString() + 'px';
animationFrame (mover);
}
mover();
Detalhes
Quando você troca de aba com o requestAnimationFrame, o processamento da animação / jogo / whatever é pausado na hora, e quando você volta, ele retorna.
Já no setInterval, hoje, pra dar uma melhor performance nos browsers, a maioria deles quando você troca de tab, ele automaticamente aumenta qualquer setInterval pra 1000 milisegundos se você ter declarado menos do que isso, e retorna ao valor inicial quando a aba é ativada novamente