Frage

Okay, ich dachte, ich hätte das ganze setTimeout-Ding perfekt, aber ich scheine mich schrecklich zu irren.

Ich verwende Excanvas und Javascript, um eine Karte meines Heimatstaates zu zeichnen, allerdings blockiert der Zeichenvorgang den Browser.Im Moment bin ich gezwungen, auf IE6 umzusteigen, weil ich in einer großen Organisation arbeite, was wahrscheinlich einen großen Teil der Langsamkeit ausmacht.

Ich dachte also, ich würde eine Prozedur namens „distributedDrawPolys“ erstellen (ich verwende dort wahrscheinlich das falsche Wort, konzentrieren Sie sich also nicht auf das Wort „distributed“), die im Grunde genommen die Polygone aus einem globalen Array herausnimmt, um 50 zu zeichnen von ihnen auf einmal.

Dies ist die Methode, die die Polygone auf das globale Array verschiebt und setTimeout ausführt:

 for (var x = 0; x < polygon.length; x++) {
      coordsObject.push(polygon[x]);
      fifty++;
      if (fifty > 49) {
           timeOutID = setTimeout(distributedDrawPolys, 5000);
           fifty = 0;
      }
 }

Ich habe am Ende dieser Methode eine Warnung eingefügt, die in praktisch einer Sekunde ausgeführt wird.

Die verteilte Methode sieht folgendermaßen aus:

 function distributedDrawPolys()
 {
      if (coordsObject.length > 0) {
           for (x = 0; x < 50; x++) { //Only do 50 polygons
                var polygon = coordsObject.pop();
                var coordinate = polygon.selectNodes("Coordinates/point");
                var zip = polygon.selectNodes("ZipCode");
                var rating = polygon.selectNodes("Score");
                if (zip[0].text.indexOf("HH") == -1) {
                     var lastOriginCoord = [];
                     for (var y = 0; y < coordinate.length; y++) {
                          var point = coordinate[y];
                          latitude = shiftLat(point.getAttribute("lat"));
                          longitude = shiftLong(point.getAttribute("long"));
                          if (y == 0) {
                               lastOriginCoord[0] = point.getAttribute("long");
                               lastOriginCoord[1] = point.getAttribute("lat");
                          }
                          if (y == 1) {
                               beginPoly(longitude, latitude);
                          }
                          if (y > 0) {
                               if (translateLongToX(longitude) > 0 && translateLongToX(longitude) < 800 && translateLatToY(latitude) > 0 && translateLatToY(latitude) < 600) {
                                    drawPolyPoint(longitude, latitude);
                               }
                          }
                     }
                     y = 0;
                     if (zip[0].text != targetZipCode) {
                          if (rating[0] != null) {
                               if (rating[0].text == "Excellent") {
                                    endPoly("rgb(0,153,0)");
                               }
                               else if (rating[0].text == "Good") {
                                    endPoly("rgb(153,204,102)");
                               }
                               else if (rating[0].text == "Average") {
                                    endPoly("rgb(255,255,153)");
                               }
                          }
                          else { endPoly("rgb(255,255,255)"); }
                     }
                     else {
                     endPoly("rgb(255,0,0)");
                     }
                }
           }
      }
 }

Bearbeiten:das Format korrigiert

Deshalb dachte ich, dass die setTimeout-Methode es der Site ermöglichen würde, die Polygone in Gruppen zu zeichnen, sodass die Benutzer mit der Seite interagieren könnten, während sie noch zeichnet.Was mache ich hier falsch?

War es hilfreich?

Lösung

Ändern Sie den Code

for (var x = 0; x < polygon.length; x++) {
    coordsObject.push(polygon[x]);
}
distributedDrawPolys();

function distributedDrawPolys()
{
    if (coordsObject.length > 0) {
        for (x = 0; x < 50; x++) {
            ...
        }
        setTimeout("distributedDrawPolys()", 5000); //render next 50 polys in 5 sec
    }
}

Andere Tipps

Wenn Ihre Schleife in weniger als einer Sekunde läuft, werden alle Ihre setTimeout Die Anrufe häufen sich und versuchen etwa fünf Sekunden später abzufeuern.

Wenn Sie dem Browser Raum für Zwischenrendering geben möchten, verschieben Sie alle Ihre Objekte auf den Stapel, rufen Sie dann die Funktion mit einem Limit auf und lassen Sie die Funktion selbst so viele Objekte einplanen, wenn sie fertig ist.Halbpseudocode:

var theArray = [];
var limit = 50;

function showStuff() {
    for (...) {
        // push objects on theArray
    }

    renderArrayInBatches();
}

function renderArrayInBatches() {
    var counter;

    for (counter = limit; counter > 0; --counter) {
        // pop an object and render it
    }
    if (theArray.length > 0) {
        setTimeout(renderArrayInBatches, 10);
    }
}

Dadurch wird das Array in einem Schritt aufgebaut und dann der erste Stapel ausgelöst (bis zu limit) des Renderings.Wenn am Ende des ersten Stapels noch mehr Rendering erforderlich ist, wird dies etwa 10 ms später geplant.Tatsächlich wird es nicht passieren früher als 10 ms später und möglicherweise auch später, wenn der Browser noch mit anderen Dingen beschäftigt ist.(Zu 10ms:Die meisten Browser planen nichts früher als 10 ms.) (Bearbeiten Andy E weist völlig richtig darauf hin, dass Sie die Logik, die sich auf das bezieht, was gerendert werden muss, genauso gut direkt in die Rendering-Funktion integrieren können, anstatt zuerst das Array zu erstellen und es dann zu verarbeiten.Ändert sich nicht viel an dem oben Gesagten, mit Ausnahme des Array-Teils; die Art und Weise, wie Sie die Verkettung durchführen, und der „Raum zum Atmen“ bleiben gleich.)

Da Sie die von Ihnen verwendeten Excanvas-Inhalte nicht kennen, müssen Sie möglicherweise die Timeout-Zeit anpassen, aber ich neige dazu, das zu bezweifeln – es handelt sich im Grunde genommen um einen „Yield“-Vorgang, der es dem Browser ermöglicht, einige Dinge zu tun und zu Ihnen zurückzukehren.

Beachten Sie, dass das obige Pseudocode-Beispiel scheinbar globale Werte verwendet.Ich würde nicht empfehlen, tatsächlich Globals zu verwenden.Vielleicht möchten Sie stattdessen sogar Folgendes tun:

function showStuff() {
    var theArray = [];
    var limit = 50;

    for (...) {
        // push objects on theArray
    }

    renderArrayInBatches();

    function renderArrayInBatches() {
        var counter;

        for (counter = limit; counter > 0; --counter) {
            // pop an object and render it
        }
        if (theArray.length > 0) {
            setTimeout(renderArrayInBatches, 10);
        }
    }
}

... aber ich wollte die Hauptantwort nicht durch die Einführung des Abschlusses verkomplizieren (obwohl technisch gesehen beide Codeblöcke Abschlüsse beinhalten).

Nein, wollen Sie etwas anderes.

var batchsize = 50; 
function drawPolys(start) {
    for (var x = start; x < polygon.length; x++) {
        drawOnePolygon(polygon[x]);
        if (start + batchsize <= x) {
            // quit this invocation, and schedule the next
            setTimeout(function(){drawPolys(x+1);}, 400);
            return;  // important
        }
    }
}

dann drawOnePolygon muss so etwas wie diese:

function drawOnePolygon(p) {
    var coordinate = polygon.selectNodes("Coordinates/point");
    //...and so on, continuing from your code above.
}

es kick off mit:

drawPolys(0); 

Wenn Sie es einmal alle fünf Sekunden anrufen, und es tut 1 Sekunde der Arbeit jedes Mal, wird der Browser für die Interaktion 20% der Zeit erstickt werden.

Sie könnten versuchen, und zerhacken Sie Ihre große Funktion und führen Sie es in Stücke, die Erfahrung glatter zu machen.

Dies ist nicht wie erwartet funktionieren. Durch die Zeit, Ihre erste Funktion startet die Ausführung, die globale Array enthält bereits 50 Elemente. Sie am Ende nur 50 Mal auf den gleichen Daten arbeiten.

Was Sie tun können, ist zu Kette Ihres SetTimeout, so dass die nächste Funktion ausführt, nach dem vorherigen Verfahren.

Hier ist eine einfache Implementierung:

var coordObj = [...]; //50 or whatever elements
(function() {
    if (coordObj.length === 0) return; //Guardian
    var obj = coordObj.pop(); //or .shift(), based on the order desired.
    doStuffWithCoordObj(obj);
    setTimeout(arguments.callee,0); //call this anonymous function after a timeout
})();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top