Angepasste Eingabeereignisse

Tapuska
Dave Tapuska

Kurzfassung

  • In Chrome 60 werden Verzögerungen reduziert, indem die Ereignishäufigkeit verringert und so die Konsistenz des Frame-Timings verbessert wird.
  • Die in Chrome 58 eingeführte Methode getCoalescedEvents() bietet die gleichen umfangreichen Ereignisinformationen, die Sie schon immer haben.

Für das Web ist es sehr wichtig, eine positive Nutzererfahrung zu bieten. Die Zeit zwischen dem Empfang eines Eingabeereignisses und der tatsächlichen Aktualisierung der Grafiken ist wichtig. Im Allgemeinen ist es dann wichtig, weniger Arbeit zu erledigen. In den letzten Chrome-Versionen haben wir die Eingabelatenz auf diesen Geräten reduziert.

Um flüssiger und leistungsfähiger zu sein, nehmen wir in Chrome 60 eine Änderung vor, durch die diese Ereignisse seltener auftreten. Gleichzeitig werden die bereitgestellten Informationen detaillierter. Ähnlich wie bei der Veröffentlichung von Jelly Bean und der Einführung des Choreographer, der die Eingabe unter Android ausrichtet, bieten wir die Frame-basierte Eingabe im Web auf allen Plattformen an.

Manchmal benötigen Sie jedoch mehr Ereignisse. Daher haben wir in Chrome 58 eine Methode namens getCoalescedEvents() implementiert, mit der Ihre Anwendung den vollständigen Pfad des Zeigers abrufen kann, auch wenn sie weniger Ereignisse empfängt.

Sprechen wir zuerst über die Häufigkeit von Ereignissen.

Ereignishäufigkeit verringern

Hier ein paar Grundlagen: Touchscreens liefern eine Eingabe mit 60–120 Hz, Mäuse normalerweise bei 100 Hz (kann aber bis zu 2.000 Hz betragen). Die typische Aktualisierungsrate eines Monitors beträgt jedoch 60 Hz. Was bedeutet das genau? Das bedeutet, dass Eingaben mit einer höheren Rate erfolgen, als die Anzeige tatsächlich aktualisiert wird. Sehen wir uns also eine Leistungszeitachse aus den Entwicklertools für eine einfache Canvas-Mal-App an.

In der folgenden Abbildung sehen Sie bei deaktivierter an requestAnimationFrame() ausgerichteter Eingabe mehrere Verarbeitungsblöcke pro Frame mit einer uneinheitlichen Framezeit. Die kleinen gelben Blöcke zeigen Treffertests für Dinge wie das Ziel des DOM-Ereignisses, das Senden des Ereignisses, das Ausführen von JavaScript, die Aktualisierung des Knotens, der mit dem Mauszeiger bewegt wird, und möglicherweise die Neuberechnung von Layout und Stilen.

Eine Leistungszeitachse mit inkonsistentem Frame-Timing

Warum machen wir zusätzliche Arbeit, die keine visuellen Aktualisierungen zur Folge hat? Idealerweise sollten wir keine Arbeiten ausführen, von denen der Nutzer letztendlich nicht profitiert. Ab Chrome 60 verzögert die Eingabepipeline das Senden kontinuierlicher Ereignisse (wheel, mousewheel, touchmove, pointermove, mousemove) und direkt vor dem requestAnimationFrame()Callback. Im Bild unten (bei aktivierter Funktion) sehen Sie eine konsistentere Frame Time und weniger Zeitverarbeitungsereignisse.

Wir haben mit dieser Funktion in den Canary- und Dev-Versionen einen Test durchgeführt und festgestellt, dass wir 35% weniger Treffertests durchführen. Dadurch kann der Hauptthread häufiger ausgeführt werden.

Beachten Sie, dass Webentwickler wissen, dass jedes einzelne Ereignis (z. B. keydown, keyup, mouseup, mousedown, touchstart, touchend) sofort zusammen mit allen ausstehenden Ereignissen gesendet wird, um die relative Reihenfolge beizubehalten. Mit dieser Funktion wird ein Großteil der Arbeit in den normalen Ereignisschleifenfluss übertragen, wodurch ein konsistentes Eingabeintervall ermöglicht wird. Dadurch werden kontinuierliche Ereignisse inline mit scroll- und resize-Ereignissen erstellt, die bereits in der Ereignisschleife in Chrome optimiert wurden.

Eine Leistungszeitachse mit relativ konsistentem Frame-Timing.

Wir haben festgestellt, dass die große Mehrheit der Anwendungen, die solche Ereignisse nutzen, die höhere Häufigkeit nicht nutzt. Android hat Ereignisse bereits seit einigen Jahren ausgerichtet, sodass es nichts Neues gibt. Websites können jedoch weniger detaillierte Ereignisse auf Desktop-Plattformen sehen. Es gab schon immer ein Problem mit instabilen Hauptthreads, die zu Problemen bei der flüssigen Eingabe führen. Dies bedeutet, dass Positionssprünge auftreten können, wenn die Anwendung arbeitet, wodurch es unmöglich ist zu wissen, wie der Zeiger von einem Punkt zum anderen gelangt ist.

Die Methode getCoalescedEvents()

Wie gesagt gibt es seltene Szenarien, in denen die Anwendung den vollständigen Pfad des Zeigers kennen möchte. Um also große Sprünge und eine geringere Häufigkeit von Ereignissen zu vermeiden, haben wir in Chrome 58 eine Erweiterung für Zeigerereignisse mit dem Namen getCoalescedEvents() eingeführt. Im folgenden Beispiel sehen Sie, wie Verzögerungen im Hauptthread in der Anwendung ausgeblendet werden, wenn Sie diese API verwenden.

Standardereignisse und zusammengeführte Ereignisse vergleichen

Anstatt ein einzelnes Ereignis zu empfangen, können Sie auf das Array der historischen Ereignisse zugreifen, die das Ereignis ausgelöst haben. Die nativen SDKs Android, iOS und Windows haben sehr ähnliche APIs und wir stellen im Web eine ähnliche API bereit.

In der Regel hat eine Zeichen-App einen Punkt anhand der Versätze des Ereignisses gezeichnet:

window.addEventListener("pointermove", function(event) {
    drawPoint(event.pageX, event.pageY);
});

Dieser Code kann einfach geändert werden, um das Ereignis-Array zu verwenden:

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 jede Property für die zusammengeführten Ereignisse ausgefüllt ist. Da die kollektiven Ereignisse nicht wirklich gesendet werden, aber gerade auf der Fahrt sind, werden sie nicht getestet. Einige Felder wie currentTarget und eventPhase haben die Standardwerte. Das Aufrufen verwandter Methoden wie stopPropagation() oder preventDefault() hat keine Auswirkungen auf das übergeordnete Ereignis.