Sie haben die Wahl zwischen mit oder ohne webWorkers:
Ohne WebWorker
Für Code, der mit dem DOM oder mit vielen anderen Status in Ihrer App interagieren muss, können Sie keinen WebWorker verwenden. Die übliche Lösung besteht darin, Ihre Arbeit in Blöcke aufzuteilen, um jeden Teil der Arbeit an einem Timer auszuführen. Die Unterbrechung zwischen Blöcken mit dem Timer ermöglicht es der Browser-Engine, andere Ereignisse zu verarbeiten, die gerade stattfinden, und ermöglicht nicht nur die Verarbeitung von Benutzereingaben, sondern auch das Zeichnen des Bildschirms.
Normalerweise können Sie es sich leisten, mehr als einen auf jedem Timer zu verarbeiten, was sowohl effizienter als auch schneller ist als nur einen pro Timer. Dieser Code gibt dem UI-Thread die Möglichkeit, ausstehende UI-Ereignisse zwischen jedem Block zu verarbeiten, wodurch die UI aktiv bleibt.
function processLargeArray(array) {
var chunk = 100;
var index = 0;
function doChunk() {
var cnt = chunk;
while (cnt-- && index < array.length) {
++index;
}
if (index < array.length) {
setTimeout(doChunk, 1);
}
}
doChunk();
}
processLargeArray(veryLargeArray);
Hier ist ein funktionierendes Beispiel für das Konzept - nicht dieselbe Funktion, sondern ein anderer Prozess mit langer Laufzeit, der dieselbe setTimeout()
Idee verwendet, um ein Wahrscheinlichkeitsszenario mit vielen Iterationen zu testen: http://jsfiddle.net/jfriend00/9hCVq/
Sie können das oben Genannte in eine allgemeinere Version umwandeln, die eine Rückruffunktion wie .forEach()
folgt aufruft :
function processLargeArrayAsync(array, fn, chunk, context) {
context = context || window;
chunk = chunk || 100;
var index = 0;
function doChunk() {
var cnt = chunk;
while (cnt-- && index < array.length) {
fn.call(context, array[index], index, array);
++index;
}
if (index < array.length) {
setTimeout(doChunk, 1);
}
}
doChunk();
}
processLargeArrayAsync(veryLargeArray, myCallback, 100);
Anstatt zu erraten, wie viele Chunks gleichzeitig benötigt werden, ist es auch möglich, die verstrichene Zeit als Leitfaden für jeden Chunk zu verwenden und so viele wie möglich in einem bestimmten Zeitintervall verarbeiten zu lassen. Dies garantiert automatisch die Reaktionsfähigkeit des Browsers, unabhängig davon, wie CPU-intensiv die Iteration ist. Anstatt eine Blockgröße zu übergeben, können Sie einen Millisekundenwert übergeben (oder einfach einen intelligenten Standard verwenden):
function processLargeArrayAsync(array, fn, maxTimePerChunk, context) {
context = context || window;
maxTimePerChunk = maxTimePerChunk || 200;
var index = 0;
function now() {
return new Date().getTime();
}
function doChunk() {
var startTime = now();
while (index < array.length && (now() - startTime) <= maxTimePerChunk) {
fn.call(context, array[index], index, array);
++index;
}
if (index < array.length) {
setTimeout(doChunk, 1);
}
}
doChunk();
}
processLargeArrayAsync(veryLargeArray, myCallback);
Mit WebWorkern
Wenn der Code in Ihrer Schleife nicht auf das DOM zugreifen muss, können Sie den gesamten zeitaufwändigen Code in einen WebWorker einfügen. Der webWorker wird unabhängig vom Hauptbrowser Javascript ausgeführt und kann dann, wenn er fertig ist, alle Ergebnisse mit einer postMessage zurückmelden.
Ein WebWorker muss den gesamten Code, der im WebWorker ausgeführt wird, in eine separate Skriptdatei aufteilen. Er kann jedoch vollständig ausgeführt werden, ohne dass die Verarbeitung anderer Ereignisse im Browser blockiert werden muss und ohne dass die Eingabeaufforderung "Nicht reagierendes Skript" erforderlich ist Dies kann auftreten, wenn ein lang laufender Prozess im Hauptthread ausgeführt wird und die Ereignisverarbeitung in der Benutzeroberfläche nicht blockiert wird.