Si usaste requestAnimationFrame, disfrutaste de ver tus pinturas sincronizadas con la frecuencia de actualización de la pantalla, lo que genera las animaciones de mayor fidelidad posible. Además, les ahorras a tus usuarios el ruido del ventilador de la CPU y la energía de la batería cuando cambian a otra pestaña.
Sin embargo, se producirá un cambio en parte de la API. La marca de tiempo que se pasa a tu función de devolución de llamada cambiará de una marca de tiempo típica similar a Date.now() a una medición de alta resolución de milisegundos de punto flotante desde que se abrió la página. Si usas este valor, deberás actualizar tu código según la explicación que se incluye a continuación.
Para que quede claro, me refiero a lo siguiente:
// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
// the value of timestamp is changing
});
Si usas la corrección de compatibilidad común de requestAnimFrame que se proporciona aquí, no estás usando el valor de la marca de tiempo. Te salvaste. :)
Por qué
¿Por qué? Bueno, rAF te ayuda a obtener los 60 fps ideales, y 60 fps se traducen en 16.7 ms por fotograma. Sin embargo, medir con milisegundos enteros significa que tenemos una precisión de 1/16 para todo lo que queremos observar y segmentar.
Como puedes ver arriba, la barra azul representa la cantidad máxima de tiempo que tienes para realizar todo tu trabajo antes de pintar un fotograma nuevo (a 60 fps). Es probable que estés haciendo más de 16 cosas, pero con milisegundos enteros solo tienes la capacidad de programar y medir en esos incrementos tan grandes. Eso no es suficiente.
El temporizador de alta resolución resuelve este problema proporcionando una cifra mucho más precisa:
Date.now() // 1337376068250
performance.now() // 20303.427000007
El temporizador de alta resolución está disponible actualmente en Chrome como window.performance.webkitNow(), y este valor suele ser igual al nuevo valor del argumento que se pasa a la devolución de llamada de rAF. Una vez que la especificación avance más en los estándares, el método descartará el prefijo y estará disponible a través de performance.now().
También notarás que los dos valores anteriores tienen muchos órdenes de magnitud diferentes. performance.now() es una medición de milisegundos de punto flotante desde que comenzó a cargarse esa página en particular (el performance.navigationStart para ser específicos).
En uso
El problema clave que surge son las bibliotecas de animación que usan este patrón de diseño:
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));
}
Una edición para corregir esto es bastante fácil: aumenta startTime y now para usar window.performance.now().
this.startTime = window.performance.now ?
(performance.now() + performance.timing.navigationStart) :
Date.now();
Esta es una implementación bastante ingenua, no usa un método now() con prefijo y también asume la compatibilidad con Date.now(), que no está en IE8.
Detección de atributos
Si no usas el patrón anterior y solo quieres identificar qué tipo de valor de devolución de llamada obtienes, puedes usar esta técnica:
requestAnimationFrame(function(timestamp){
if (timestamp < 1e12){
// .. high resolution timer
} else {
// integer milliseconds since unix epoch
}
// ...
Verificar if (timestamp < 1e12) es una prueba rápida para ver con qué número estamos lidiando. Técnicamente, podría dar un falso positivo, pero solo si una página web está abierta de forma continua durante 30 años. Sin embargo, no podemos probar si es un número de punto flotante (en lugar de un número entero). Si solicitas suficientes temporizadores de alta resolución, obtendrás valores enteros en algún momento.
Planeamos lanzar este cambio en Chrome 21, por lo que, si ya estás aprovechando este parámetro de devolución de llamada, asegúrate de actualizar tu código.