Si vous utilisiez requestAnimationFrame
, vous aimiez voir vos peintures synchronisées avec la fréquence d'actualisation de l'écran, ce qui vous permettait de créer les animations les plus fidèles possibles. De plus, vous économisez le bruit du ventilateur du processeur et la batterie de vos utilisateurs lorsqu'ils passent à un autre onglet.
Une partie de l'API va toutefois être modifiée. L'horodatage transmis à votre fonction de rappel passe d'un code temporel Date.now()
typique à une mesure haute résolution en millisecondes à virgule flottante depuis l'ouverture de la page. Si vous utilisez cette valeur, vous devrez mettre à jour votre code, conformément à l'explication ci-dessous.
Pour être clair, voici ce dont je parle:
// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
// the value of timestamp is changing
});
Si vous utilisez le shim requestAnimFrame
commun fourni ici, vous n'utilisez pas la valeur d'horodatage. Vous n'êtes pas concerné. :)
Pourquoi
Pourquoi ? Eh bien, rAF vous aide à atteindre les 60 FPS idéaux, ce qui correspond à 16,7 ms par image. Mais en mesurant avec des nombres entiers en millisecondes, nous avons une précision de 1/16 pour tout ce que nous voulons observer et cibler.
Comme vous pouvez le voir ci-dessus, la barre bleue représente le temps maximal dont vous disposez pour effectuer tout votre travail avant de peindre un nouveau frame (à 60 FPS). Vous effectuez probablement plus de 16 tâches, mais avec des millisecondes entières, vous ne pouvez planifier et mesurer que ces incréments très importants. Ce n'est pas suffisant.
Le minuteur haute résolution résout ce problème en fournissant un chiffre beaucoup plus précis:
Date.now() // 1337376068250
performance.now() // 20303.427000007
Le minuteur haute résolution est actuellement disponible dans Chrome sous la forme window.performance.webkitNow()
. Cette valeur est généralement égale à la nouvelle valeur d'argument transmise au rappel rAF. Une fois que la spécification progresse dans les normes, la méthode supprime le préfixe et sera disponible via performance.now()
.
Vous remarquerez également que les deux valeurs ci-dessus sont très différentes. performance.now()
correspond à une mesure en millisecondes à virgule flottante depuis le début du chargement de cette page spécifique (performance.navigationStart
, plus précisément).
Utilisées
Le principal problème concerne les bibliothèques d'animation qui utilisent ce modèle de conception:
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));
}
La correction est assez simple : modifiez startTime
et now
pour utiliser window.performance.now()
.
this.startTime = window.performance.now ?
(performance.now() + performance.timing.navigationStart) :
Date.now();
Il s'agit d'une implémentation assez naïve. Elle n'utilise pas de méthode now()
préfixée et suppose également la prise en charge de Date.now()
, qui n'est pas disponible dans IE8.
Détection de fonctionnalités
Si vous n'utilisez pas le modèle ci-dessus et que vous souhaitez simplement identifier le type de valeur de rappel que vous obtenez, vous pouvez utiliser cette technique:
requestAnimationFrame(function(timestamp){
if (timestamp < 1e12){
// .. high resolution timer
} else {
// integer milliseconds since unix epoch
}
// ...
Vérifier if (timestamp < 1e12)
permet de tester rapidement la taille d'un nombre donné. Techniquement, il peut s'agir d'un faux positif, mais uniquement si une page Web est ouverte en continu pendant 30 ans. Toutefois, nous ne pouvons pas vérifier s'il s'agit d'un nombre à virgule flottante (plutôt que d'un entier arrondi). Demandez suffisamment de minuteurs haute résolution, et vous obtiendrez à un moment donné des valeurs entières.
Nous prévoyons de déployer ce changement dans Chrome 21. Par conséquent, si vous utilisez déjà ce paramètre de rappel, veillez à mettre à jour votre code.