3

わかりました、私はこの setTimeout 全体が完璧だと思っていましたが、ひどく間違っているようです。

Excanvas と JavaScript を使用して自宅の州の地図を描画していますが、描画手順がブラウザーを詰まらせます。現在、私は大きな組織に所属しているため、IE6 に甘んじることを余儀なくされています。

だから私がやろうと思ったのは、distributedDrawPolys と呼ばれる手順を構築することです (おそらく間違った単語を使用しているので、distributed という単語には注目しないでください)。一度にそれらの。

これは、ポリゴンをグローバル配列にプッシュし、setTimeout を実行するメソッドです。

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

そのメソッドの最後にアラートを配置しました。実際には 1 秒で実行されます。

分散メソッドは次のようになります。

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

編集:フォーマットを修正

そのため、setTimeout メソッドを使用すると、サイトがポリゴンをグループで描画できるようになり、ユーザーはページがまだ描画されている間にページを操作できるようになると考えました。ここで何が間違っていますか?

4

5 に答える 5

7

ループが 1 秒未満で実行されている場合、すべてのsetTimeout呼び出しがスタックして、約 5 秒後に起動しようとします。

ブラウザーに中間レンダリングの余裕を持たせたい場合は、すべてのオブジェクトをスタックにプッシュしてから、制限付きで関数を呼び出し、その数のオブジェクトが終了したときに関数自体をスケジュールします。準擬似コード:

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

limitこれにより、配列がすべて一度に構築され、レンダリングの最初のバッチ (最大 ) がトリガーされます。最初のバッチの最後に、さらにレンダリングが必要な場合は、約 10 ミリ秒後に実行されるようにスケジュールされます。実際、ブラウザがまだ他のことでビジー状態である場合は、10 ミリ秒以内に発生する可能性が高く、それよりも遅く発生する可能性があります(Re 10ms: ほとんどのブラウザーは、今から 10ms よりも早く何かをスケジュールすることはありません。) (編集Andy E は、レンダリングする必要があるものに関連するロジックをレンダリング関数に直接折りたたむのではなく、かなり正確に指摘しています。最初に配列を構築してから処理するよりも. 配列部分を除いて上記をあまり変更しません, 連鎖を行う方法と「息抜きの部屋」は同じままです.)

使用しているexcanvasの内容がわからない場合は、タイムアウト時間を調整する必要があることに気付くかもしれませんが、私はそれを疑う傾向があります.

上記の疑似コード サンプルでは、​​グローバルと思われるものを使用していることに注意してください。実際にグローバルを使用することはお勧めしません。代わりにこれをしたいかもしれません:

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

...しかし、クロージャーを導入して主な答えを複雑にするのは好きではありませんでした (ただし、技術的には両方のコードブロックにクロージャーが含まれます)。

于 2010-03-16T14:09:04.693 に答える
3

コードを次のように変更します

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
    }
}
于 2010-03-16T14:09:13.363 に答える
1

いいえ、何か違うものが必要です。

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

その場合、drawOnePolygonは次のようになります。

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

キックオフ:

drawPolys(0); 
于 2010-03-16T14:12:34.800 に答える
0

これは期待どおりに機能しません。最初の関数の実行が開始されるまでに、グローバル配列にはすでに50個の要素が含まれています。同じデータを50回操作することになります。

できることは、setTimeoutをチェーンして、前のメソッドの後に次の関数が実行されるようにすることです。

簡単な実装は次のとおりです。

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
})();
于 2010-03-16T14:10:09.213 に答える
0

5 秒ごとに 1 回呼び出し、毎回 1 秒間処理すると、ブラウザは 20% の確率でインタラクションのためにチョークされます。

大きな関数を切り刻み、チャンクで実行して、エクスペリエンスをよりスムーズにすることができます。

于 2010-03-16T14:23:35.670 に答える