Question

D'accord, je pensais avoir tout ce truc setTimeout parfait, mais il me semble être horriblement trompé.

J'utilise excanvas et javascript pour dessiner une carte de mon pays d'origine, mais la procédure de dessin étrangle le navigateur. En ce moment, je suis obligé de se plier aux exigences IE6 parce que je suis dans une grande organisation, ce qui est probablement une grande partie de la lenteur.

Alors, ce que je pensais que je ferais est de construire une procédure appelée distributedDrawPolys (j'utilise probablement le mauvais mot là-bas, donc ne pas se concentrer sur le mot distribué) qui apparaît essentiellement les polygones hors d'un tableau global pour à tirer 50 d'entre eux à la fois.

Ceci est la méthode qui pousse les polygones sur le tableau global et exécute le setTimeout:

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

Je mets une alerte à la fin de cette méthode, il fonctionne dans pratiquement une seconde.

La méthode distribuée ressemble à:

 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)");
                     }
                }
           }
      }
 }

Edit: fixe le format

Je pensais que la méthode setTimeout permettrait au site de dessiner les polygones en groupes afin que les utilisateurs seraient en mesure d'interagir avec la page alors qu'il dessinait encore. Qu'est-ce que je fais mal ici?

Était-ce utile?

La solution

Modifiez le 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
    }
}

Autres conseils

Si votre boucle est en cours d'exécution en moins d'une seconde, tous vos appels setTimeout se cumulera à essayer de déclencher environ cinq secondes plus tard.

Si vous voulez donner à la salle de respiration du navigateur pour le rendu intermédiaire, pousser tous vos objets sur la pile, puis appeler la fonction avec une limite, et que le calendrier de la fonction elle-même quand il est fait que de nombreux objets. Semi-pseudocode:

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);
    }
}

Ce builds le tableau en une seule fois, déclenche alors le premier lot (jusqu'à limit) de rendu. A la fin du premier lot, s'il y a plus d'un rendu à faire, il planifie pour arriver sur les 10ms plus tard. En fait, il se produira pas plus tôt que 10ms plus tard et peut-être plus tard, si le navigateur est toujours occupé avec d'autres choses. (Re 10ms. La plupart des navigateurs ne seront pas planifier quelque chose pour plus tôt que 10ms à partir de maintenant) ( Modifier Andy E souligne, à juste titre, que vous pouvez aussi bien plier la logique liée à ce qui doit être rendu dans la fonction de rendu directement plutôt que de construire d'abord le tableau, le traitement il. cela ne change pas ce qui précède beaucoup, sauf pour la partie de tableau, la façon dont vous faites l'enchaînement et la « salle de respiration » reste le même.)

Ne connaissant pas les excanvas choses que vous utilisez, vous pouvez vous trouver besoin d'ajuster le temps de délai d'attente, mais je tendance à en douter - il est essentiellement une opération de « rendement », qui permet au navigateur de faire certaines choses et revenir à vous.

Notez que l'échantillon pseudo-code ci-dessus utilise ce qui semble être globals. Je ne recommanderais pas vraiment en utilisant globals. Vous pouvez même le faire à la place:

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);
        }
    }
}

... mais je n'aime pas compliquer la réponse principale en introduisant la fermeture (bien que techniquement les deux codeblocks impliquent des fermetures).

Non, vous voulez quelque chose de différent.

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
        }
    }
}

alors drawOnePolygon doit être quelque chose comme ceci:

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

le coup d'envoi avec:

drawPolys(0); 

Si vous appelez une fois toutes les cinq secondes, et il fait 1 seconde de travail à chaque fois, le navigateur sera étranglé d'interaction 20% du temps.

Vous pouvez essayer de couper votre grande fonction et l'exécuter en morceaux pour rendre l'expérience plus lisse.

Cela ne fonctionne pas comme prévu. Au moment où votre première fonction commence à exécuter, votre tableau global contient déjà 50 éléments. Vous venez de finir par fonctionner sur les mêmes données 50 fois.

Ce que vous pouvez faire est de votre chaîne setTimeout de telle sorte que la fonction suivante exécute après la méthode précédente.

Voici une implémentation simple:

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
})();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top