Como usar requestAnimationFrame ao invés de setInterval

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

2 thoughts on “Como usar requestAnimationFrame ao invés de setInterval

  1. Olá Danilo, boa tarde.

    Estou estudando htm5 e box2d focado no desenvolvimento de jogos, porem estou tendo um pouco de dificuldades em encontrar algo em relacao ao box2d
    se vc puder me ajudar fico grato.
    :)

  2. Na realidade essa técnica se torna útil, por exemplo, quando o site executa uma animação pesada e quando o usuário troca a guia ou minimiza o navegador a função para de ser executada.
    Como o próprio nome diz ela é feita para animações, logo em jogos deve-se ter ou um loop com setTimeout/setInterval para o loop de jogabilidade e o requestAnimationFrame para a animação do mesmo.
    O que me lembra da época que eu estava criando um site com um player e pensei em usar essa função para atualizar o título da página: não funciona, pois quando o usuário troca a guia a música continua, mas a função para de rodar.

Leave a Reply

Your email address will not be published. Required fields are marked *