Zeit ist Geld – Traue keinem Flex-Timer

Bei der Arbeit an meinem aktuellen Projekt ist mir aufgefallen, dass die Flex-Timer nicht so genau arbeiten, wie ich das gern hätte. Ich habe die Timer-Klasse zwar schon ein paar Mal eingesetzt, aber da kam es nicht so auf Genauigkeit an, weswegen ich auch nie ein Problem festgestellt habe. Nun gab es aber pro Minute teilweise Abweichungen von 5 Sekunden! Für eine Stoppuhr ist das viel zu ungenau. Also habe ich ein wenig nachgeforscht, wo diese Differenz herkommt und eine kleine Beispielanwendung geschrieben, um das Problem zu verdeutlichen.

Der einfachste Ansatz die Zeit in Flex zu messen, ist sicher die Verwendung der Timer-Klasse mit einem relativ kleinen Intervall von zum Beispiel 250ms. Das ganze sieht dann ungefähr so aus:

private var timer:Timer = null;
private var time:Number = 0;
private var intervall:int = 250;

override protected function createChildren():void {
    super.createChildren();

    timer = new Timer(_interval);
    timer.addEventListener(TimerEvent.TIMER, timerTick);
}

protected function timerTick(event:TimerEvent):void {
    time = time + intervall;
}

public function startTimer():void {
    timer.start();
}

 

Man sollte nun meinen, dass in der Variable time ein genauer Wert der abgelaufenen Zeit gespeichert wird. Dem ist jedoch nicht so! Das kann jeder gern mit seiner Stoppuhr überprüfen. Die Zeit scheint in Flex etwas langsamer zu vergehen. Arbeitet der Flash-Player in einem Schwarzen Loch?

Offensichtlich hat die Ausführung des Eventhandlers einen Einfluss auf den Timer. Verarbeitet man viele Daten, bietet es sich an diese Logik über die callLater-Methode aufzurufen, damit der Timer unmittelbar fortfahren kann. Er wartet sonst auf das Result des Eventhandlers. Das wirkt sich selbst bei sehr kleinen Funktionen aus und summiert sich.

Meine Beispielanwendung demonstriert diese Effekte (Download). Sie dient dem Vergleich eines Timers (Time Count), der die Sekunden zählt, einem Intervall (Interval Count), der gleiches tut aber per setInterval aufgerufen wird und einem Timer (Time Diff), der die abgelaufene Zeit berechnet.

Möchte man also, dass ein Timer genauer läuft, so muss man das Intervall, in dem der Eventhandler aufgerufen werden soll, dynamisch anpassen (siehe auch hier).

protected function timerTick(event:TimerEvent):void {
    var offset:int = time % interval;
    timer.delay = offset < 500 ? interval - offset : interval;
}

Und was lernen wir daraus? Niemals Zeit zählen! Immer die Differenz zwischen zwei Zeitpunkten berechnen und das Timer-Intervall dynamisch anpassen 😉

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.