Timeout

Zeit-gesteuerte Ereignisse in Javascript

Javascript bietet Funktionen zur Auslösung zeitgesteuerter Ereignisse (events). Davon wird z.B. bei Animationen Gebrauch gemacht.
Javascript Webseiten-Programmiersprache, Datum & Zeit
Timeout-Demo Live-Demonstration von Timeout-Ereignissen
Programmierung von Timeout-Ereignissen in Javascript
Sonderfälle Unterbrechung, Abbruch, mehrere Timeout-Ereignisse
Zähler mit Timeout-Ereignissen
Flush Aktualisierung der Webseite mit einem Trick
Verwandte Themen Millisekunden-Log (Aufzeichnung schneller Vorgänge mit Javascript)
Timeout in Perl

Timeout

Ereignisse

Ereignisse sind die treibende Kraft aller modernen Programme. Wenn sie die Maus bewegen oder mit ihr ein Objekt anklicken, dann werden Ereignisse (events) ausgelöst, auf die ein Programm reagieren kann. test

Ein Timeout ist ein Ereignis (event), welches nach Ablauf einer bestimmten Zeit ausgelöst wird.
Mit Klick auf den Start-Button lösen sie eine 6 Sekunden lange Kette von Javascript-Ereignissen aus.
   
   
0

Programmierung von Timeout-Ereignissen

Das Beispiel rechts zeigt die Programmierung. Funktion start_timeout setzt das Timeout-Ereignis mit der Methode setTimeout des windows-Objekts.
Die Methode verlangt 2 Argumente: Den Namen der auszuführenden Javascript-Funktion und die Wartezeit in Millisekunden (ms).
Es ist nicht vorgesehen, mit Javascript ein Ereignis zu einem bestimmten Datum oder zu einer bestimmten Zeit auszulösen. Solche Funktionen werden zur Systemverwaltung benötigt, nicht jedoch für Webseiten.

Die Auslösung kann auf unterschiedliche Weise erfolgen:
+ Durch unmittelbare Ausführung einer Javascript-Anweisung beim Laden der Webseite (hier durch //Kommentar abgeschaltet).
+ Durch Aufruf aus einer Javascript-Funktion
+ Interaktiv (nächster Absatz)
Javascript:
<script type="text/javascript">
function start_timeout() {
window.setTimeout("do_alert()",2000);
}

function do_alert() {
alert("Timeout");
}

// start_timeout();
</script>
Das Beispiel rechts zeigt 2 Möglichkeiten, eine beliebige Javascript-Funktion interaktiv (durch Anklicken) auszulösen - Hier wird start_timeout gestartet.
Der Hyperlink <a></a> kann an einen Text oder eine Grafik gebunden werden, der <button> wird als solcher dargestellt.
Nach dem Klicken müssen sie 2 Sekunden auf das Ereignis warten - In dieser Zeit passiert nichts !
HTML:
<a href="javascript:start_timeout()"> Start</a>
<button onclick="start_timeout()">

</button>

Psychologie

Geben sie den BesucherInnen ihrer Webseiten immer Informationen darüber, wass passiert.
Wenn sie längere Timeouts auslösen (>1 sec), dann sollte das wartende Ereignis auf der Webseite angezeigt werden.
Im ersten Beispiel oben übernimmt diese Funktion ein Sekunden-Zähler, in diesem Beispiel wird der Hinweis-Text auffällig gefärbt.
Alle hier gezeigten Beispiele wurden mit Javascript-DOM-Methoden und mit CSS erstellt.

Spezielle Programmierung von Timeout-Aufträgen

Unterbrechung

Leider reagieren gängige Browser unterschiedlich auf Unterbrechungen. Wenn während eines wartenden Timeout-Auftrags ein Fenster (Alarm, Dialog) geöffnet wird, dann reagieren Browser unterschiedlich:
Browser der Gecko-Familie (Firefox, Mozilla, Netscape, ..) reagieren wie erwartet: Der Auftrag wird zeitgerecht abgewickelt, unabhängig von anderen Ereignissen.
M$IE und Opera unterbrechen den Ablauf und warten, bis das Fenster geschlossen wird. Das widerspricht zwar jeder Theorie und Praxis der Programmierung, ist aber Tatsache.
Beispiel:
Das Beispiel ändert die Hintergrund-Farbe und öffnet nach 1 sec ein Alarm-Fenster.
Nach weiteren 1 sec wird die Hintergrund-Farbe zurückgesetzt:
Testen sie, ob das Ereignis in 2 sec abläuft wie geplant, oder erst nach dem Schließen des Alarmfensters.
Details der Demo zur Unterbrechung:
Mit Klick auf den Start-Button wird Funktion demo_3a ausgelöst. Dort wird der Hintergrund auf #FF0=gelb gesetzt, danach werden 2 Timeout-Aufträge gestartet:

Ein Timeout startet nach 1 sec Funktion demo_3b, ein Alarmfenster wird angezeigt.

Ein weiterer Timeout nach 2 sec startet Funktion demo_3c, damit wird die Hintergrund-Farbe wieder auf #FFF=weiss gesetzt. Unsauber arbeitende Browser verzögern diesen Timeout.

Eine Möglichkeit, auch mit M$IE halbwegs korrekte Timeouts zu programmieren, ist die zusätzliche Kontrolle der aktuellen Zeit. Wenn ein Fenster nach Unterbrechung wieder aktiv ist, kann damit ein laufender Timeout verkürzt oder abgebrochen werden.
Javascript-Quelltext:
function demo_3a(){
demo_4.style.backgroundColor="#FF0";
window.setTimeout("demo_3b()",1000);
window.setTimeout("demo_3c()",2000);
}
function demo_3b() {
alert("Alarmfenster");
}
function demo_3c() {
demo_4.style.backgroundColor="#FFF";
}

Abbruch

Jeder wartende Timeout-Auftrag kann auch abgebrochen worden. Dazu wird der Rückgabe-Wert der Timeout-Aufträge genutzt.
Methode window.clearTimeout löscht jenen Auftrag, der als Argument übergeben wird.
Der Rückgabe-Wert wird am besten an eine globale Variable übergeben, damit er in jeder Funktion verfügbar ist.
var evt5 = null;
function demo_5_start() {
evt5 = window.setTimeout(...);
}
function demo_5_stop() {
window.clearTimeout(evt5);
}
 

Mehrere Timeout-Aufträge

Fast beliebig viele verschiedene Timeout-Aufträge können gleichzeitig beauftragt werden.
Wenn keine Unterbrechung eintritt, dann werden sie unabhängig voneinander ausgeführt.
Während der Laufzeit können sie mit Hilfe jener Variablen gesteuert werden, die beim Start zurückgegeben werden.
Klicken sie Start für eine automatische Demo, oder klicken sie jeden einzelnen Button, um die Ereignisse zu beliebigen Zeitpunkten auszulösen.
evt_61 = window.setTimeout(...,1000);
evt_62 = window.setTimeout(...,2000);
evt_63 = window.setTimeout(...,3000);

 

Zähler mit Timeout-Ereignissen

Live-Demonstration:

0
Im HTML Quelltext richten sie ein beliebiges Element als Zähler ein. Das Element muss ein eindeutiges id-Attribut erhalten (hier counter ).
Eine Änderung des Zählerstands betrifft nicht das Element selbst, sondern sein einziges child-Element - einen Text-Knoten mit dem Anfangs-Wert "0" !
HTML:
<span id="counter">0</span>

Globale Variable

Der Zählerstand wird in einer Variablen (hier counter_value ) gespeichert und anfangs auf 0 gesetzt.
In einer weiteren Variablen (hier counter_onoff ) wird der Zustand (ein oder aus) des Zählers verwaltet.
Beide Variablen müssen für alle Funktionen zur Verfügung stehen. Sie werden daher global definiert, d.h. außerhalb irgendeiner function
Javascript: globale Variable
var counter_value = 0;
var counter_onoff = false;

Zähler-Start

Rechts ein einfaches Beispiel zum Start des Zählers. Der Zustand (Variable counter_onoff ) wird eingeschaltet, danach die eigentliche Zähl-Funktion counter_count aufgerufen.
Javascript: Start (vereinfacht)
function counter_start() {
counter_onoff = true;
counter_count(1);
}

Zähler

Das Beispiel zeigt den eigentlichen Zähler.
Er darf nur im eingeschalteten Zustand zählen, d.h. nur wenn counter_off==true
Der Zähler-Wert counter_value wird um den Betrag dc erhöht. Mit dc=1 wird der Zähler um +1 erhöht. Andere Werte erlauben größere Schritte, negative Werte zählen abwärts.
Mit dem Hilfsprogramm counter_display (unten) wird der Zählerstand auf der Webseite abgezeigt.
Zuletzt wird ein Timeout gesetzt (hier nach 1000ms = 1 sec), welcher die gleiche Funktion aufruft, d.h. weiter zählt - ohne sonstige Anweisungen 'unendlich' lange.
Javascript-Zähler
function counter_count(dc) {
if(counter_onoff) {
counter_value+=dc;
counter_display();
var func = "counter_count("+dc+")";
ec = window.setTimeout(func,1000);
}
}

Stop und Reset

Der Zähler kann mit 2 verschiedenen Methoden angehalten werden:
Zuerst wird der Zustand ( counter_off ) abgeschaltet.
Mit clearTimeout wird ein allenfalls noch laufender Auftrag abgeschaltet.
Das kann zu einem Fehler führen, wenn gerade kein Zähler-Auftrag läuft. Deshalb wird die Anweisung in einem try-Block eingeschlossen. Die catch-Anweisung bleibt leer.
Mit counter_reset kann man den Zählerstand zurückstellen - unabhängig davon, ob er gerade läuft oder nicht.
Javascript: Stop und Reset
function counter_stop() {
counter_onoff = false;
try{window.clearTimeout(ec);}
catch(e) {}
}

function counter_reset() {
counter_value = 0;
counter_display();
}

Start

Dieses Beispiel zeigt eine verbesserte Start-Version:
Die Schrittweite des Zählers dc wird als Argument an die Funktion übergeben, und zwar nicht in der einfachen Form
function counter_start(dc) {...}  
Der Wert des Arguments dc wird aus dem Array arguments entnommen, welches für jede function definiert ist.
Wenn kein Argument übergeben wurde, dann wird der Standardwert dc=+1 verwendet.
Vor dem Start wird sichergestellt, dass allfällig noch laufende Zähler-Aufträge sicher beendet werden.
Zuletzt wird der eigentliche Zähler counter_count gestartet.
Javascript: Start
function counter_start() {
var dc = 1;
if (counter_start.arguments.length>0) {
dc = counter_start.arguments[0];
}
counter_onoff = false;
try{window.clearTimeout(ec);}
catch(e) {}
counter_onoff = true;
counter_count(dc);
}
Anwendung:
counter_start(1)   // count up
counter_start(-1)   // count down

Zählerstand anzeigen

Das Beispiel zeigt ein Hilfsprogramm, welches den aktuellen Zählerstand auf der Webseite Live anzeigt.
Dazu wird das Zähler-Element id="counter" adressiert (siehe Absatz HTML dieses Kapitels).
Der erste child-Knoten des Elements (ein Text-Knoten) enthält den Zählerstand - Dieser Text wird geändert.

Details zu DOM-Methoden (Adressierung von Elementen, Live-Änderung von Webseiten).
Javascript: Hilfsprogramm
function counter_display() {
var n = document.getElementById("counter");
n.firstChild.nodeValue = counter_value.toString();
}

Flush mit Timeout

Live-Demonstration

Ausführung einer länger laufenden Programm-Schleife (Dauer je nach PC-Leistung):

Während das Programm läuft, wird hier ein Hinweis angezeigt:
Leider gibt es keine direkte Möglichkeit, den Browser zu einer Aktualisierung der Webseite zu veranlassen. Hier wird dazu ein Trick vorgestellt.
Wenn eine (dynamische) Webseite geändert wurde, dann wird sie von jedem Browser automatisch aktualisiert. Das erfolgt zwar zuverlässig - allerdings nur dann, wenn der Browser "Zeit dazu hat".
Wenn der Browser ein länger (einige Sekunden) laufendes Javascript-Programm ausführt, dann erfolgt die Aktualisierung erst nach dem Ende des Programms. Es gibt keine Möglichkeit, den Browser bereits vorher zu einer Aktualisierung (Flush) zu bewegen.
Gerade bei länger laufenden Programmen ist es jedoch unbedingt notwendig, die/den AnwenderIn davon zu informieren - Das ist sinnlos, wenn der Hinweis erst nach Ende des Programms angezeigt wird.

Szenario

Sie wollen ein länger laufendes Javascript-Programm ausführen.
Zu Beginn soll auf der Webseite ein Hinweis angezeigt werden.
Nach Abschluss des Programms soll der Hinweis wieder gelöscht werden.
Dazu wird ein Hinweis in den HTML-Quelltext eingefügt, dessen CSS-Eigenschaft Sichtbarkeit mit Javascript abwechselnd ein- und ausgeschaltet wird.
HTML
<div id="hinweis" style="display:none">
Bitte um Geduld !
</div>
Javascript:
function hinweis(onoff) {
var n=document.getElementById("hinweis");
if(onoff) {n.style.display="inline";}
else {n.style.display="none";}
}

Anwendung

Das Beispiel rechts zeigt die geplante Anwendung: Der Hinweis wird eingeschaltet und bleibt sichtbar, solange das Programm läuft. Zuletzt wird der Hinweis wieder abgeschaltet.
Javascript: arbeitet nicht wie gewünscht !
hinweis(true);
// lange laufendes Programm
hinweis(false);
Leider funktioniert das nicht: Weil der Browser zu beschäftigt ist, wird die Anweisung hinweis(true); nur formal ausgeführt. Weil die Seite nicht aktualisiert wird, ist der Hinweis nicht sichtbar ! Nach Ende des Javascript-Programms wird der Hinweis mit hinweis(false); abgeschaltet. Erst jetzt hat der Browser Zeit und aktualisiert die Webseite.
Im Effekt wird daher die Warnung erst angezeigt, wenn sie schon wieder abgeschaltet wurde - d.h. gar nicht.

Flush mit Timeout

Der Trick besteht darin, das Javascript-Programm zu teilen:
Im ersten Teil wird lediglich der Hinweis eingeschaltet. Danach gibt man dem Browser Zeit zur Aktualisierung. Einige Millisekunden genügen.
Der zweite Teil wird mit Timeout gestartet, führt das Programm aus und schaltet zuletzt den Hinweis ab.
Javascript: so funktioniert es !
hinweis(true);
window.setTimeout("weiter()",10);

function weiter() {
// lange laufendes Programm
hinweis(false);
}

Flush mit Anker-Link

Bei Sprung zu einem Anker-Link (auf der gleichen Webseite) wird die Anzeige ebenfalls von jedem Browser aktualisiert.
Diesen Trick sollten sie jedoch nur dann anwenden, wenn sichergestellt ist, dass sich die angezeigte Webseite bereits genau bei diesem Link befindet - ansonsten ruckt die Seite bei Ausführung des Programms.
HTML: Ein Anker-Link auf der gleichen Webseite
<a id="anker1" name="anker1"></a>
Javascript: Aktualisierung funktioniert mit Vorbehalt.
hinweis(true);
location.replace("anker1");
// lange laufendes Programm
hinweis(false);