Se você já usou requestAnimationFrame
, deve ter notado que as pinturas são sincronizadas com a taxa de atualização da tela, resultando nas animações de maior fidelidade possíveis. Além disso, você economiza a energia da bateria e o ruído do ventilador da CPU quando os usuários mudam para outra guia.
No entanto, uma parte da API está prestes a mudar. O carimbo de data/hora transmitido para a função de callback muda de um carimbo de data/hora típico do tipo Date.now()
para uma medição de alta resolução de milissegundos de ponto flutuante desde que a página foi aberta. Se você usar esse valor, vai precisar atualizar seu código com base na explicação abaixo.
Para deixar claro, estou falando sobre o seguinte:
// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
// the value of timestamp is changing
});
Se você estiver usando o shim requestAnimFrame
comum fornecido aqui, não estará usando o valor do carimbo de data/hora. Você está livre. :)
Por quê?
Por quê? O rAF ajuda você a atingir a taxa ideal de 60 QPS, que equivale a 16,7 ms por frame. No entanto, medir com milissegundos inteiros significa que temos uma precisão de 1/16 para tudo o que queremos observar e segmentar.
Como você pode ver acima, a barra azul representa o tempo máximo que você tem para fazer todo o trabalho antes de pintar um novo frame (a 60 fps). Você provavelmente está fazendo mais de 16 coisas, mas com milissegundos inteiros, só é possível programar e medir nesses incrementos muito grandes. Isso não é bom o suficiente.
O High Resolution Timer resolve isso fornecendo uma figura muito mais precisa:
Date.now() // 1337376068250
performance.now() // 20303.427000007
O timer de alta resolução está disponível no Chrome como window.performance.webkitNow()
, e esse valor geralmente é igual ao novo valor do argumento transmitido para o callback rAF. Quando a especificação for implementada nos padrões, o método vai remover o prefixo e ficar disponível em performance.now()
.
Você também vai notar que os dois valores acima são muito diferentes. performance.now()
é uma medição de milissegundos de ponto flutuante desde que a página começou a carregar (o performance.navigationStart
, para ser específico).
Em uso
O principal problema são as bibliotecas de animação que usam este padrão de design:
function MyAnimation(duration) {
this.startTime = Date.now();
this.duration = duration;
requestAnimFrame(this.tick.bind(this));
}
MyAnimation.prototype.tick = function(time) {
var now = Date.now();
if (time > now) {
this.dispatchEvent("ended");
return;
}
...
requestAnimFrame(this.tick.bind(this));
}
A edição para corrigir isso é bem fácil... aumente o startTime
e o now
para usar window.performance.now()
.
this.startTime = window.performance.now ?
(performance.now() + performance.timing.navigationStart) :
Date.now();
Essa é uma implementação bastante simples, que não usa um método now()
com prefixo e também pressupõe suporte a Date.now()
, que não está no IE8.
Detecção de recursos
Se você não estiver usando o padrão acima e quiser apenas identificar o tipo de valor de callback que está recebendo, use esta técnica:
requestAnimationFrame(function(timestamp){
if (timestamp < 1e12){
// .. high resolution timer
} else {
// integer milliseconds since unix epoch
}
// ...
A verificação de if (timestamp < 1e12)
é um teste rápido para sabermos o tamanho do número com que estamos lidando. Tecnicamente, isso pode ser um falso positivo, mas apenas se uma página da Web permanecer aberta continuamente por 30 anos. Mas não é possível testar se é um número de ponto flutuante (em vez de ser arredondado para um número inteiro). Peça timers de alta resolução suficientes e você vai receber valores inteiros em algum momento.
Planejamos fazer essa mudança no Chrome 21. Se você já estiver usando esse parâmetro de callback, atualize seu código.