Web Performance: Wenn auf die Millisekunde genau nicht genau genug ist

Manchmal ist es einfach nicht genau genug, Zeit in Millisekunden zu messen. Gemeinsam mit führenden Vertretern aus der Branche und der Community hat die Web Performance-Arbeitsgruppe des W3C durch die Standardisierung der High Resolution Time-Spezifikation an einer Lösung dieses Problems gearbeitet. Diese Woche wurde die Spezifikation als Proposed Recommendation (PR) veröffentlicht, die von vielen modernen Browsern unterstützt wird. Sehen Sie sich in der Test Drive-Demo What Time is it? die API in Aktion an.

Diese Spezifikation wurde in nur acht Monaten von einer Idee zu einer PR entwickelt. Die PR-Stufe der Standardisierung ist der letzte Schritt, bevor ein Webstandard den Status einer offiziellen „W3C Recommendation“ erhält. Zudem wurde diese Schnittstelle weitgehend in Browsern übernommen, einschließlich vollem Support in Internet Explorer 10, Firefox 15 und Unterstützung mit Präfix in Chrome 22. Dies ist ein herausragendes Beispiel für eine gelungene Zusammenarbeit der Branche und der Community über das W3C.

Aber warum sind Millisekunden nicht gut genug? Zeit wurde im Web seit Langem mit einer Variante des „Date“-Objekts von JavaScript gemessen, entweder über die „Date.now()“-Methode oder den „DOMTimeStamp“-Typ. Das „Date“-Objekt gibt einen Zeitwert in Millisekunden ab dem 1. Januar 1970 UTC an. In den meisten Anwendungen war diese Definiton ausreichend, um einen beliebigen Zeitpunkt bis zu 285.616 Jahren nach dem 1. Januar 1970 UTC anzugeben.

Beispielsweise lag mein „Date.now()“-Zeitwert während des Schreibens dieses Blog-Beitrags für meine IE10-Entwicklungstoolskonsole bei 1350509874902. Diese dreizehnstellige Zahl gibt die Anzahl der Millisekunden an, die seit dem 1. Januar 1970 vergangen sind, und entspricht dem 17. Oktober 2012, 21:37:54 UTC.

Diese Definition wird weiter nützlich zur Bestimmung des aktuellen Datums sein, jedoch gibt es einige Fälle, in denen dies nicht ausreicht. Beispielsweise möchten Entwickler gerne ermitteln, ob Animationen konstant mit 60 Frames pro Sekunde ausgeführt werden (d. h. alle 16,667 Millisekunden wird ein Frame dargestellt). Mithilfe der einfachen Methode zum Berechnen der aktuellen FPS, der Bestimmung des letzen Callbacks für die Framedarstellung, lässt sich nur ein FPS-Wert von 58,8 FPS (1/17) oder 62,5 FPS (1/16) ermitteln.

Ebenso sind Berechnungen in einem Bereich, der über Millisekunden herausgeht, wünschenswert, wenn es darum geht, verstrichene Zeit (z. B. mithilfe der Navigation Timing-, Resource Timing- und User Timing-APIs für Netzwerk- und Skript-Timing) zu bestimmen, oder beim Synchronisieren von animierten Szenen bzw. Audio und Animation.

Dieses Problem wird durch die „High Resolution Time“-Spezifikation behoben, die eine neue Zeitauflösung unterhalb von Millisekunden (1/1000 einer Millisekunde) definiert. Um die Anzahl erforderlicher Bits zu verringern und die Lesbarkeit zu erhöhen, wird hierbei nicht die Zeit ab dem 1. Januar 1970 UTC gemessen, sondern die Zeit ab dem Start der Dokumentnavigation (performance.timing.navigationStart).

Die Spezifikation definiert „performance.now()“ analog zur Methode „Date.now()“ für die präzise Bestimmung der aktuellen Zeit. Der „DOMHighResTimeStamp“-Typ wird analog zum „DOMTimeStamp“ gebildet, der den genauen Zeitwert definiert.

Beispielsweise erhalte ich die folgenden beiden Werte, wenn ich die aktuelle Zeit während des Schreibens dieses Blog-Beitrags mithilfe von „performance.now()“ und „Date.now()“ in der IE10-Entwicklungstoolskonsole abrufe:

 performance.now():        196.304879519774
Date.now():        1350509874902

Obwohl diese beiden Zeitwerte denselben Zeitpunkt angeben, erfolgt die Messung auf Grundlage einer anderen Basis. Der „performance.now()“-Zeitwert wirkt deutlich lesbarer.

Da „High Resolution Time“-Werte ab dem Start der Dokumentnavigation gemessen werden, erfolgt die Messung von „performance.now()“ in einem untergeordneten Dokument ab dem Start der Dokumentnavigation im untergeordneten Dokument und nicht im Stammdokument. Nehmen wir beispielsweise an, dass ein Dokument über den nicht ursprungsübergreifenden „iframe A“ und den ursprungsübergreifenden „iframe B“ verfügt. Hierbei soll die Navigation in „iframe A“ ca. 5 Millisekunden nach dem Start der Navigation des Stammdokuments erfolgt sein und analog dazu ca. 10 Millisekunden nach dem Start der Navigation des Stammdokuments für „iframe B“. Wenn wir den genauen Zeitpunkt 15 Millisekunden nach dem Start der Navigation im Stammdokument ermitteln, erhalten wir für „performance.now()“-Aufrufe in unterschiedlichen Kontexten die folgenden Werte:

performance.now() in iframe B:                                5,123 ms

performance.now() in iframe A:                               10,123 ms

performance.now() im Stammdokument:                    15,123 ms

Date.now() in einem beliebigen Kontext:                         134639846051 ms

Abbildung, die den Unterschied zwischen „Date.now()“- und „performance.now()“-Messungen darstelltAbbildung: „Date.now()“ wird ab dem 1. Januar 1970 gemessen, „performance.now()“ ab dem Start der Dokumentnavigation

Dieser Entwurf stellt nicht nur sicher, dass es beim Erstellen des übergeordneten Elements in ursprungsübergreifenden iframes nicht zu Datenverlusten kommt, sondern ermöglicht zugleich das Bestimmen der Zeit relativ zu Ihrem Start. Wenn Sie beispielsweise die „Resource Timing“-Schnittstelle verwenden (die wiederum „High Resolution Time“ verwendet), um zu bestimmen, wie lange ein Server für eine Antwort auf eine Ressourcenanforderung in einem untergeordneten Dokument benötigt, müssen Sie keine Anpassungen vornehmen, um die Dauer des Hinzufügens des untergeordneten Dokuments zum Stammdokument zu berücksichtigen.

Wenn Sie Zeiten Frame-übergreifend vergleichen möchten, müssen Sie lediglich „top.performance.now()“ anfordern, um einen Zeitwert relativ zum Start der Navigation im Stammdokument zu erhalten, da derselbe Wert für alle nicht ursprungsübergreifenden iframes zurückgegeben wird.

Ein weiterer deutlicher Vorteil der API gegenüber „Date.now()“ ist, dass „performance.now()“ monoton steigt und somit unabhängig von Abweichungen bei der Uhrzeit ist. Der Unterschied zwischen aufeinander folgenden „performance.now()“-Aufrufen kann niemals negativ sein. Bei „Date.now()“ besteht keine solche Garantie, und es wurde bereits über Fälle berichtet, bei denen negative Zeitwerte in Analysedaten aufgetaucht sind.

„High Resolution Time“ ist ein großartiges Beispiel dafür, wie schnell sich neue Ideen zu interoperablen Standards entwickeln können, die für Entwickler in modernen HTML5-fähigen Browsern verlässlich sind. Vielen Dank an alle Mitarbeiter in der Web Performance-Arbeitsgruppe des W3C für die Unterstützung bei der Entwicklung dieser API und an alle Browserhersteller, die diese API im Rahmen der fortschreitenden Interoperabilität implementiert haben.

Vielen Dank
Jatinder Mann
Internet Explorer Program Manager