Unerlaubte Vervielfältigung ist untersagt
1. Bearbeitung teurer Berechnungen
Der vielleicht komplexeste Aspekt bei der Entwicklung komplexer Javascript-Anwendungen ist der Single-Thread-Charakter der Benutzeroberfläche. Die beste Situation, wenn Javascript die Benutzerinteraktion verarbeitet, ist eine langsame Reaktion, und die schlimmste Situation ist eine fehlende Reaktion, die dazu führt, dass der Browser hängt (wenn Javascript ausgeführt wird, werden alle Aktualisierungsvorgänge auf der Seite angehalten). Aus diesem Grund ist es zwingend erforderlich, alle komplexen Vorgänge (jede Berechnung, die länger als 100 ms dauert) auf ein überschaubares Maß zu reduzieren. Wenn das Skript nach mindestens fünf Sekunden Ausführung nicht stoppt, generieren einige Browser (z. B. Firefox und Opera) außerdem eine Eingabeaufforderung, um den Benutzer zu warnen, dass das Skript nicht reagiert.
Dies ist offensichtlich unerwünscht und es ist nicht gut, eine nicht reagierende Schnittstelle zu erzeugen. Dies ist jedoch mit ziemlicher Sicherheit der Fall, wenn Sie große Datenmengen verarbeiten müssen (z. B. die Verarbeitung Tausender DOM-Elemente).
Zu diesem Zeitpunkt ist der Timer besonders nützlich. Da der Timer die Ausführung von Javascript-Code effektiv anhalten kann, kann er auch verhindern, dass der Browser den ausgeführten Code hängen lässt (solange der einzelne Code nicht ausreicht, um den Browser zum Hängen zu bringen). Vor diesem Hintergrund können wir normale, intensive Schleifenberechnungen in nicht blockierende Berechnungen integrieren. Schauen wir uns das folgende Beispiel an, in dem diese Art von Berechnung erforderlich ist.
Eine Daueraufgabe:
<table><tbody></tbody></table>
// Normaler, intensiver Betrieb
var table = document.getElementsByTagName("tbody");
for ( var i = 0; i < 2000; i++ ) {
var tr = document.createElement("tr");
for ( var t = 0; t < 6; t++ ){
var td = document.createElement("td");
td.appendChild(document.createTextNode("" + t));
tr.appendChild(td);
}
table.appendChild(tr);
}
}
In diesem Beispiel erstellen wir insgesamt 26.000 DOM-Knoten und tragen die Zahlen in eine Tabelle ein. Dies ist zu teuer und wird höchstwahrscheinlich den Browser blockieren und die normale Benutzerinteraktion verhindern. Wir können hier Timer einführen und andere, vielleicht bessere Ergebnisse erzielen.
Verwenden Sie Timer, um lang laufende Aufgaben zu unterbrechen:
<table><tbody></tbody></table>
var table = document.getElementsByTagName("tbody");
var i = 0, max = 1999;
setTimeout(function(){
for ( var step = i + 500; i < step; i++ ) {
var tr = document.createElement("tr");
for ( var t = 0; t < 6; t++ ){
var td = document.createElement("td");
td.appendChild(document.createTextNode("" + t));
tr.appendChild(td);
}
}
table.appendChild(tr);
}
wenn (i < max)
setTimeout( arguments.callee, 0 );
}, 0);
In unserem modifizierten Beispiel haben wir die intensive Berechnung in vier Teile aufgeteilt, wobei jeder 6500 Knoten erstellt. Es ist unwahrscheinlich, dass diese Berechnungen den normalen Ablauf des Browsers unterbrechen. Das schlimmste Szenario besteht darin, dass diese Zahlen jederzeit angepasst werden können (sie beispielsweise zwischen 250 und 500 variieren, sodass jede unserer Zellen 3500 DOM-Knoten generiert). Am beeindruckendsten ist jedoch, wie wir unseren Code geändert haben, um ihn an das neue asynchrone System anzupassen. Wir müssen noch mehr Arbeit leisten, um sicherzustellen, dass die Zahlen für die Elemente korrekt generiert werden (die Schleife endet nicht für immer). Der Code ist unserem Original sehr ähnlich. Beachten Sie, dass wir Abschlüsse verwenden, um den Iterationsstatus zwischen Codefragmenten aufrechtzuerhalten. Ohne Abschlüsse wird dieser Code zweifellos komplexer sein.
Im Vergleich zum Original gibt es bei dieser Technologie eine deutliche Veränderung. Lange Browser-Hänge werden durch 4 visuelle Seitenaktualisierungen ersetzt. Obwohl der Browser versucht, diese Codeschnipsel so schnell wie möglich auszuführen, rendert er auch DOM-Änderungen (wie massive Updates) nach jedem Schritt des Timers. In den meisten Fällen sind sich Benutzer dieser Art von Aktualisierungen nicht bewusst, es ist jedoch wichtig, sich daran zu erinnern, dass sie stattfinden.
Es gibt eine Situation, in der diese Technologie speziell für mich funktionieren würde – eine Anwendung, die ich entwickelt habe, um die Stundenpläne von Studenten zu berechnen. Zunächst handelte es sich bei der Anwendung um eine typische CGI-Anwendung (der Client sprach mit dem Server, der Server berechnete den Zeitplan und gab ihn zurück). Aber ich habe es geändert und alle Zeitplanberechnungen auf dem Client abgelegt. Dies ist die Ansicht der Zeitplanberechnungen:
Diese Berechnungen sind recht aufwendig (Tausende Permutationen müssen durchlaufen werden, um die richtige Antwort zu finden). Dieses Problem wird gelöst, indem die Zeitplanberechnung in tatsächliche Einheiten aufgeteilt wird (Aktualisierung der Benutzeroberfläche mit dem abgeschlossenen Teil). Am Ende lieferten die Benutzer eine Benutzeroberfläche, die schnell, reaktionsschnell und benutzerfreundlich war.
Es ist oft überraschend, wie nützlich Technologie sein kann. Sie werden es häufig in Programmen mit langer Laufzeit wie Testboxen verwenden (wir besprechen dies am Ende dieses Kapitels). Noch wichtiger ist, dass uns diese Technologie zeigt, wie einfach es ist, die Einschränkungen der Browserumgebung zu umgehen und den Benutzern gleichzeitig ein umfassendes Erlebnis zu bieten.