Kurzfassung
- In Chrome 60 wird das Ruckeln durch eine geringere Ereignishäufigkeit reduziert, wodurch das Frame-Timing einheitlicher wird.
- Die in Chrome 58 eingeführte Methode
getCoalescedEvents()
bietet dieselben umfangreichen Ereignisinformationen wie bisher.
Eine reibungslose Nutzererfahrung ist im Web wichtig. Die Zeit zwischen dem Empfang eines Eingabeereignisses und der tatsächlichen Aktualisierung der visuellen Elemente ist wichtig. Außerdem ist es wichtig, möglichst wenig Arbeit zu leisten. In den letzten Releases von Chrome haben wir die Eingabelatenz auf diesen Geräten weiter gesenkt.
In Chrome 60 nehmen wir eine Änderung vor, um die Nutzerfreundlichkeit und Leistung zu verbessern. Dadurch treten diese Ereignisse seltener auf, die bereitgestellten Informationen sind aber detaillierter. Ähnlich wie bei der Veröffentlichung von Jelly Bean und der Einführung von Choreographer, mit dem die Eingabe auf Android-Geräten ausgerichtet wird, führen wir die framebasierte Eingabe auf allen Plattformen im Web ein.
Manchmal benötigen Sie jedoch mehr Ereignisse. Deshalb haben wir in Chrome 58 die Methode getCoalescedEvents()
implementiert. Damit kann Ihre Anwendung den vollständigen Pfad des Cursors abrufen, auch wenn weniger Ereignisse empfangen werden.
Sehen wir uns zuerst die Ereignishäufigkeit an.
Ereignishäufigkeit senken
Sehen wir uns einige Grundlagen an: Touchscreens liefern Eingaben mit 60–120 Hz und Mäuse liefern Eingaben in der Regel mit 100 Hz (kann aber bis zu 2.000 Hz betragen). Die typische Aktualisierungsrate eines Monitors liegt jedoch bei 60 Hz. Was bedeutet das? Das bedeutet, dass wir Eingaben mit einer höheren Rate erhalten, als das Display aktualisiert wird. Sehen wir uns also eine Leistungszeitachse aus den DevTools für eine einfache Canvas-Malanwendung an.
Auf dem Bild unten ist die requestAnimationFrame()
-ausgerichtete Eingabe deaktiviert. Es sind mehrere Verarbeitungsblöcke pro Frame mit einer inkonsistenten Framezeit zu sehen.
Die kleinen gelben Blöcke geben Aufschluss über Treffertests für Dinge wie das Ziel des DOM-Ereignisses, das Senden des Ereignisses, das Ausführen von JavaScript, das Aktualisieren des Mauszeiger-Knotens und das eventuelle Neuberechnen von Layout und Stilen.
Warum machen wir also zusätzliche Arbeit, die keine visuellen Änderungen zur Folge hat? Idealerweise möchten wir keine Arbeit leisten, die letztendlich nicht dem Nutzer zugutekommt. Ab Chrome 60 verzögert die Eingabepipeline das Senden kontinuierlicher Ereignisse (wheel
, mousewheel
, touchmove
, pointermove
, mousemove
) und sendet sie direkt vor dem requestAnimationFrame()
-Callback. Auf dem Bild unten (mit aktivierter Funktion) sehen Sie eine gleichmäßigere Framezeit und eine kürzere Verarbeitungszeit für Ereignisse.
Wir haben einen Test mit dieser Funktion auf den Canary- und Dev-Kanälen durchgeführt und festgestellt, dass wir 35% weniger Treffertests ausführen. Dadurch kann der Hauptthread häufiger ausgeführt werden.
Webentwickler sollten beachten, dass jedes diskrete Ereignis (z. B. keydown
, keyup
, mouseup
, mousedown
, touchstart
, touchend
) sofort zusammen mit allen ausstehenden Ereignissen gesendet wird, wobei die relative Reihenfolge beibehalten wird. Wenn diese Funktion aktiviert ist, wird ein Großteil der Arbeit in den normalen Ereignis-Loop eingebunden, wodurch ein einheitliches Eingabeintervall entsteht. So werden fortlaufende Ereignisse mit scroll
- und resize
-Ereignissen in Einklang gebracht, die bereits in den Ablauf des Ereignis-Loops in Chrome integriert wurden.
Wir haben festgestellt, dass die überwiegende Mehrheit der Anwendungen, die solche Ereignisse nutzen, die höhere Häufigkeit nicht benötigt. Auf Android-Geräten werden Ereignisse bereits seit einigen Jahren angeglichen. Auf Desktop-Plattformen sind die Ereignisse jedoch möglicherweise weniger detailliert. Es gab immer ein Problem mit ruckeligen Hauptthreads, die zu Rucklern bei der Eingabe führen. Das bedeutet, dass die Position manchmal springt, wenn die Anwendung aktiv ist, sodass nicht klar ist, wie der Cursor von einer Stelle zur anderen gelangt ist.
Die Methode getCoalescedEvents()
Wie bereits erwähnt, gibt es seltene Szenarien, in denen die Anwendung den vollständigen Pfad des Zeigers kennen sollte. Um große Sprünge und die verringerte Häufigkeit von Ereignissen zu beheben, haben wir in Chrome 58 eine Erweiterung für Zeiger-Ereignisse namens getCoalescedEvents()
eingeführt. Unten sehen Sie ein Beispiel dafür, wie Ruckler im Hauptthread von der Anwendung ausgeblendet werden, wenn Sie diese API verwenden.
Anstatt ein einzelnes Ereignis zu erhalten, können Sie auf die Reihe der bisherigen Ereignisse zugreifen, die das Ereignis verursacht haben. Android, iOS und Windows haben in ihren nativen SDKs sehr ähnliche APIs. Wir stellen eine ähnliche API für das Web bereit.
In einer Zeichenanwendung wird in der Regel ein Punkt gezeichnet, indem die Abweichungen des Ereignisses betrachtet werden:
window.addEventListener("pointermove", function(event) {
drawPoint(event.pageX, event.pageY);
});
Dieser Code kann ganz einfach so geändert werden, dass das Ereignisarray verwendet wird:
window.addEventListener("pointermove", function(event) {
var events = 'getCoalescedEvents' in event ? event.getCoalescedEvents() : [event];
for (let e of events) {
drawPoint(e.pageX, e.pageY);
}
});
Beachten Sie, dass nicht alle Properties in den zusammengeführten Ereignissen ausgefüllt sind. Da die zusammengeführten Ereignisse nicht wirklich gesendet werden, sondern nur mitgenommen werden, werden sie nicht auf Treffer getestet. Einige Felder wie currentTarget
und eventPhase
haben ihre Standardwerte. Das Aufrufen von Methoden, die sich auf die Zustellung beziehen, wie stopPropagation()
oder preventDefault()
, hat keine Auswirkungen auf das übergeordnete Ereignis.