2008-10-17 2 views
21

Ich habe den Beitrag here über die Verwendung von setTimeout() während der intensiven DOM-Verarbeitung (mit JavaScript) gelesen, aber wie kann ich diese Funktion mit dem folgenden Code integrieren? Der folgende Code funktioniert gut für eine kleine Anzahl von Optionen, aber wenn die Anzahl der Optionen zu groß wird, bleibt mein animiertes GIF "Bitte warten" stehen, während das lokale JavaScript verarbeitet wird. Vielen Dank!Wie kann ich dem Browser während intensiver JavaScript-Verarbeitung die Kontrolle zurückgeben (kurz)?

function appendToSelect() { 
    $("#mySelect").children().remove() ; 
    $("#mySelect").html(
     '<option selected value="' + obj.data[0].value + '">' 
     + obj.data[0].name 
     + '</option>' 
    ); 
    var j = 1 ; 
    for (var i = 1; i < obj.data.length; i++) { 
     $("#mySelect").append(
      '<option value="' + obj.data[i].value + '">' 
      + obj.data[i].name 
      + '</option>' 
     ); 
    } 
} 
+2

sagen Sie ihnen, um Chrome zu verwenden, und sie werden JITted Javascript haben :) –

Antwort

28

ist eine Lösung:

function appendToSelect() { 
    $("#mySelect").children().remove(); 
    $("#mySelect").html(
    '<option selected value="'+obj.data[0].value+'">' 
    + obj.data[0].name 
    + '</option>' 
); 
    obj.data.splice(0, 1); // we only want remaining data 
    var appendOptions = function() { 
    var dataChunk = obj.data.splice(0, 10); // configure this last number (the size of the 'chunk') to suit your needs 
    for(var i = 0; i < dataChunk.length; i++) { 
     $("#mySelect").append(
     '<option value="' + dataChunk[i].value + '">' 
     + dataChunk[i].name 
     + '</option>' 
    ); 
    } 
    if(obj.data.length > 0) { 
     setTimeout(appendOptions, 100); // change time to suit needs 
    } 
    }; 
    appendOptions(); // kicks it off 
} 

nicht so elegant wie @Borgar's Lösung, aber Sie bekommen die Idee. Im Grunde genommen tue ich dasselbe, aber alles in Ihrer einen Funktion, anstatt sie in eine Funktion höherer Ordnung zu zerlegen, so wie er es tut. Ich mag seine Lösung, aber wenn du es nicht tust, wird das vielleicht für dich funktionieren.


EDIT: Für diejenigen, die es nicht sofort sehen, einer der wichtigsten Unterschiede zwischen dieser Lösung und @Borgar's ist, dass diese Lösung die Größe der ‚Brocken‘ von Daten festlegen können, die zwischen verarbeitet wird jedes Zeitlimit @Borgar's Timeout nach jedes einzelne Mitglied des Arrays wird verarbeitet. Wenn ich Zeit bekomme, werde ich versuchen, eine Funktion höherer Ordnung zu erstellen, um damit umzugehen, so dass es eleganter ist. Keine Versprechungen obwohl! ;)


EDIT: So, hier ist meine Anpassung der @Borgar's Lösung, die leicht zum Einstellen eines 'Chunk' Größe und Konfiguration der Timeout-Wert mehr erlaubt:

function incrementallyProcess(workerCallback, data, chunkSize, timeout, completionCallback) { 
    var itemIndex = 0; 
    (function() { 
    var remainingDataLength = (data.length - itemIndex); 
    var currentChunkSize = (remainingDataLength >= chunkSize) ? chunkSize : remainingDataLength; 
    if(itemIndex < data.length) { 
     while(currentChunkSize--) { 
     workerCallback(data[itemIndex++]); 
     } 
     setTimeout(arguments.callee, timeout); 
    } else if(completionCallback) { 
     completionCallback(); 
    } 
    })(); 
} 

function appendToSelect() { 
    $("#mySelect").children().remove(); 
    $("#mySelect").html(
    '<option selected value="' + obj.data[0].value + '">' 
    + obj.data[0].name 
    + '</option>' 
); 
    obj.data.splice(0,1); // we only want remaining data  
    incrementallyProcess(function(data) { 
    $("#mySelect").append(
    '<option value="' + data.value + '">' 
    + data.name 
    + '</option>' 
    ); 
    }, obj.data, 10, 100, removeAnimatedGifFunction); // last function not required... 
} 

Hoffe, das hilft - I denke, dass dies das Beste aus beiden Lösungen kombiniert. Hinweis, die zweite anonyme Funktion verwendet nicht mehr den Indexwert, sondern übergibt einfach das gesamte Objekt (mit den Eigenschaften Wert und Name). das macht es ein wenig sauberer, da der Index des aktuellen Objekts wirklich nicht in der Regel ist, dass nützlich beim Iterieren über Dinge, IMO.

Ich bin mir sicher, dass es noch Dinge gibt, die getan werden können, um dies noch besser zu machen, aber das ist eine Übung für den Leser. ;)

-1

Sie müßten die Funktion neu zu schreiben, die Elementliste cachen, dann Schleife über die Liste einen Zähler von einer Art verwendet wird.

Wenn der Zähler den Zähler% max_num_before_wait == 0 erreicht, rufen Sie das Timeout zurück zur Funktion selbst.

Stellen Sie sicher, dass Sie den Cache und den Zähler am Ende der vollständigen Liste löschen, oder verwenden Sie eine sekundäre Funktion mit einem zusätzlichen Zählparameter.

20

Es ist einfach so, dass ich gerade vor einem Moment here postete. Hier ist eine zeitlich Loop-Funktion:

function processLoop(actionFunc, numTimes, doneFunc) { 
    var i = 0; 
    var f = function() { 
    if (i < numTimes) { 
     actionFunc(i++); // closure on i 
     setTimeout(f, 10) 
    } 
    else if (doneFunc) { 
     doneFunc(); 
    } 
    }; 
    f(); 
} 

Für Ihre Situation dies wie folgt verwendet werden würde:

function appendToSelect() { 

    $("#mySelect").children().remove() ; 
    $("#mySelect").html(
     '<option selected value="' + obj.data[0].value + '">' 
     + obj.data[0].name 
     + '</option>' 
); 
    var j = 1 ; 

    processLoop(function (i){ 
    $("#mySelect").append(
     '<option value="' + obj.data[i].value + '">' 
     + obj.data[i].name 
     + '</option>' 
    ); 
    }, obj.data.length); 

} 

Sie wollen werden, um sicherzustellen, dass Sie einen Verschluss haben oder einen anderen Zugriff auf den obj Variable innerhalb der Iterationsfunktion.

Hoffe, das hilft. Hier

4

Wenn Sie etwas einfacheres brauchen, schrieb ich ein jQuery-Plugin, um das Schreiben von asynchronen Schleifen zu erleichtern: jQuery Async.

Mit dem Plugin können Sie den Code neu geschrieben werden als:

function appendToSelect() { 
    $("#mySelect").children().remove() ; 
    $("#mySelect").html(
     '<option selected value="' + obj.data[0].value + '">' 
     + obj.data[0].name 
     + '</option>' 
    ); 

    ///////////////////////////// 
    var i = 1; 
    $.whileAsync({ 
     test: function(){ i < obj.data.length; } 
     loop: function() 
     { 
      $("#mySelect").append(
       '<option value="' + obj.data[i].value + '">' 
       + obj.data[i].name 
       + '</option>' 
      ); 
      i++; 
     } 
    }); 
    ///////////////////////////// 
} 

die Reaktions helfen sollte. Optimieren Sie die Optionen "Bulk" und "Delay" für mehr Kontrolle.

Verwandte Themen