Vor Kurzem habe ich an der Verarbeitung einer recht umfangreichen Tabelle per Javascript gearbeitet und dabei tat sich das Problem auf, wie ich dem Benutzer am einfachsten den Fortschritt visualisieren konnte.
Gegeben war eine Tabelle mit zwei Spalten. Die erste namens nr, beinhaltete die laufende Nummer des Eintrags und die zweite, namens entry, den zu verarbeitenden Wert. Jede Zelle besaß eine eindeutige ID, die ebenfalls die fortlaufende Nummer enthielt, um die einzelnen Zellen darüber ansprechen zu können:
<input id="txtCount" type="hidden" value="..."/>
<span id="lblProcess" />
<table>
<tr>
<td id="nr_1">1</td>
<td id="entry_1">...</td>
</tr>
<tr>
<td id="nr_2">2</td>
<td id="entry_2">...</td>
</tr>
...
</table>
Meine Idee war nun, ein über der Tabelle befindliches Label mit der Nummer des aktuell zu verarbeitenden Eintrags zu aktualisieren..
(Der folgende Code setzt auf dem freien Javascript-Framework jQuery auf)
function processTableData() {
// Anzahl der zu verarbeitenden Einträge ermitteln
var iCount = parseInt($("#txtCount").val());
// Schleifen
if (iCount != 0) {
for (i = 1; i < (iCount + 1); i++) {
// aktualisieren des Labels
$("#lblProcess").html('Verarbeitung von Eintrag ' + i);
// Verarbeitung durchführen
//...
}
}
}
Das Ganze hatte leider einen Haken: die Browser arbeiten immer erst eine Javascript-Operation komplett ab, bevor sie den Inhalt der Seite neu rendern, d.h. die Methode lief durch und das Label wurde erst am Ende mit dem letzten Eintrag aktualisiert. Nicht wirklich der Sinn eines Fortschrittsanzeigers.
Da Javascript leider keine Methode kennt, mit man das Rendern erzwingen kann, war nach etwas Recherche der einzige Ansatz die setTimeout-Methode, denn diese führt nach einer bestimmten Verzögerungszeit die übergebene Methode aus. Die Schleife setzt im Prinzip nur Funktionsaufrufe ab, die zur angegebenen Zeit ausgeführt werden.
function processTableData() {
// Anzahl der zu verarbeitenden Einträge ermitteln
var iCount = parseInt($("#txtCount").val());
// Schleife
if (iCount != 0) {
for (i = 1; i < (iCount + 1); i++) {
setTimeout('doProcess(' + i + ')', 20 * (i+1));
}
}
}
function doProcess(i) {
// aktualisieren des Labels
$("#lblProcess").html('Verarbeitung von Eintrag ' + i);
// Verarbeitung durchführen
//...
}
Der Trick an der Lösung ist nun, dass jeder Aufruf von setTimeout eine um i versetzte Startzeit erhält. Der erste Aufruf läuft nach 20 Millisekunden los, der zweite nach 40, der dritte nach 60 und so weiter. In der Zeit zwischen den Aufrufen hat der Browser Zeit das Label zu aktualisieren.
Resultat ist, dass im Label die fortlaufende Nummer durchrattert und der Benutzer ein Gefühl dafür bekommt, wie lange es noch dauert.