Als je requestAnimationFrame gebruikt, heb je vast gemerkt dat je tekeningen worden gesynchroniseerd met de vernieuwingssnelheid van het scherm, wat de meest natuurgetrouwe animaties oplevert. Bovendien bespaar je je gebruikers CPU-ventilatorgeluid en batterijvermogen als ze naar een ander tabblad gaan.
Er komt binnenkort wel een wijziging in een deel van de API. De tijdstempel die wordt doorgegeven aan je callbackfunctie, verandert van een typische Date.now()-achtige tijdstempel in een meting met hoge resolutie van milliseconden met drijvende komma sinds de pagina is geopend. Als u deze waarde gebruikt, moet u uw code updaten op basis van de uitleg hieronder.
Voor de duidelijkheid: dit is waar ik het over heb:
// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
// the value of timestamp is changing
});
Als u de algemene requestAnimFrame-shim gebruikt die hier wordt verstrekt, gebruikt u de tijdstempelwaarde niet. Je bent van de haak. :)
Waarom
Waarom? Met rAF kun je de ultieme 60 fps bereiken, wat ideaal is.60 fps komt neer op 16,7 ms per frame. Maar als we meten met gehele milliseconden, hebben we een precisie van 1/16 voor alles wat we willen observeren en targeten.
Zoals je hierboven kunt zien, geeft de blauwe balk de maximale tijd aan die je hebt om al je werk te doen voordat je een nieuw frame tekent (bij 60 fps). U doet waarschijnlijk meer dan 16 dingen, maar met gehele milliseconden kunt u alleen plannen en meten in die zeer grote stappen. Dat is niet goed genoeg.
De High Resolution Timer lost dit op door een veel nauwkeuriger cijfer te geven:
Date.now() // 1337376068250
performance.now() // 20303.427000007
De timer met hoge resolutie is op dit moment beschikbaar in Chrome als window.performance.webkitNow(). Deze waarde is over het algemeen gelijk aan de nieuwe argumentwaarde die wordt doorgegeven aan de rAF-callback. Zodra de specificatie verder is ontwikkeld, wordt het voorvoegsel verwijderd en is de methode beschikbaar via performance.now().
U merkt ook dat de 2 bovenstaande waarden veel orden van grootte verschillen. performance.now() is een meting van milliseconden met drijvende komma sinds die specifieke pagina is begonnen met laden (de performance.navigationStart om precies te zijn).
In gebruik
Het belangrijkste probleem dat zich voordoet, zijn animatiebibliotheken die dit ontwerppatroon gebruiken:
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));
}
Je kunt dit vrij makkelijk aanpassen: breid de startTime en now uit om window.performance.now() te gebruiken.
this.startTime = window.performance.now ?
(performance.now() + performance.timing.navigationStart) :
Date.now();
Dit is een vrij naïeve implementatie. Er wordt geen methode met voorvoegsel now() gebruikt en er wordt ook uitgegaan van ondersteuning voor Date.now(), wat niet in IE8 zit.
Functiedetectie
Als u het bovenstaande patroon niet gebruikt en alleen wilt vaststellen welk type callback-waarde u krijgt, kunt u deze techniek gebruiken:
requestAnimationFrame(function(timestamp){
if (timestamp < 1e12){
// .. high resolution timer
} else {
// integer milliseconds since unix epoch
}
// ...
if (timestamp < 1e12) controleren is een snelle test om te zien hoe groot het getal is waarmee we te maken hebben. Technisch gezien kan dit een fout-positief resultaat opleveren, maar alleen als een webpagina 30 jaar lang onafgebroken openstaat. We kunnen niet testen of het een zwevende-kommagetal is (in plaats van een geheel getal). Als je genoeg timers met hoge resolutie vraagt, krijg je op een gegeven moment gehele waarden.
We zijn van plan deze wijziging door te voeren in Chrome 21. Als u deze callback-parameter al gebruikt, moet u uw code updaten.