25

私はJSスクリプトにそのような機能を持っています:

function heavyWork(){
   for (i=0; i<300; i++){
        doSomethingHeavy(i);
   }
}

「doSomethingHeavy」自体は問題ないかもしれませんが、それを 300 回繰り返すと、ブラウザ ウィンドウが無視できない時間スタックします。Chrome では、タブが 1 つしか影響を受けないため、それほど大きな問題ではありません。しかし、Firefox にとっては完全な惨事です。

doSomethingHeavy の呼び出しの間にすべてをブロックしないように、ブラウザ/JS に「簡単に」指示する方法はありますか?

4

9 に答える 9

24

setTimeout呼び出し内に呼び出しをネストできます。

for(...) {
    setTimeout(function(i) {
        return function() { doSomethingHeavy(i); }
    }(i), 0);
}

これにより、呼び出しがdoSomethingHeavyすぐに実行されるようにキューに入れられますが、他の JavaScript 操作はそれらの間に割り込むことができます。

より良い解決策は、ブラウザーがWeb Workersを介して新しいノンブロッキング プロセスを実際に生成することですが、これは HTML5 固有のものです。

編集:

を使用するsetTimeout(fn, 0)と、実際には 0 ミリ秒よりもはるかに長い時間がかかります。たとえば、Firefox では、最小 4 ミリ秒の待機時間が強制されます。より良いアプローチは、 setZeroTimeoutpostMessageを使用することです。これは、即時の割り込み可能な関数呼び出しを好みますがsetTimeout、古いブラウザーのフォールバックとして使用します。

于 2012-04-16T19:34:01.550 に答える
13

setTimeoutタイムアウト 0 で、各関数呼び出しを でラップしてみることができます。これにより、呼び出しがスタックの一番下にプッシュされ、ブラウザーは各呼び出しの間で休むことができます。

function heavyWork(){
   for (i=0; i<300; i++){
        setTimeout(function(){
            doSomethingHeavy(i);
        }, 0);
   }
}

編集:これが機能しないことに気付きました。ループのi反復ごとに値が同じになるため、クロージャーを作成する必要があります。

function heavyWork(){
   for (i=0; i<300; i++){
        setTimeout((function(x){
            return function(){
                doSomethingHeavy(x);
            };
        })(i), 0);
   }
}
于 2012-04-16T19:32:09.287 に答える
10

Web ワーカーを使用する必要があります

https://developer.mozilla.org/En/Using_web_workers

Googleで検索すると、Webワーカーに関するリンクがたくさんあります

于 2012-04-16T19:33:03.267 に答える
3

ブラウザの注意を独占しないように、時々ブラウザに制御を解放する必要があります。

制御を解放する 1 つの方法は、 を使用することsetTimeoutです。これは、ある期間に呼び出される「コールバック」をスケジュールします。例えば:

var f1 = function() {
    document.body.appendChild(document.createTextNode("Hello"));
    setTimeout(f2, 1000);
};

var f2 = function() {
    document.body.appendChild(document.createTextNode("World"));
};

ここで呼び出すと、ドキュメントにf1単語が追加helloされ、保留中の計算がスケジュールされ、制御がブラウザーに解放されます。最終的に、f2呼び出されます。

setTimeoutあたかも魔法の妖精の粉であるかのように、プログラム全体に無差別にまき散らすだけでは不十分であることに注意してください。残りの計算をコールバックにカプセル化する必要があります。通常、 はsetTimeout関数の最後にあり、残りの計算はコールバックに詰め込まれます。

特定のケースでは、コードを次のように慎重に変換する必要があります。

var heavyWork = function(i, onSuccess) {
   if (i < 300) {
       var restOfComputation = function() {
           return heavyWork(i+1, onSuccess);
       }
       return doSomethingHeavy(i, restOfComputation);          
   } else {
       onSuccess();
   }
};

var restOfComputation = function(i, callback) {
   // ... do some work, followed by:
   setTimeout(callback, 0);
};

これにより、すべてのブラウザに制御が解放されますrestOfComputation

この別の具体的な例として、以下を参照してください:一連のサウンド HTML5 <audio> サウンド クリップをキューに入れ、順番に再生するにはどうすればよいですか?

上級の JavaScript プログラマーは、このプログラム変換を行う方法を知っている必要があります。この手法を使用すると、制御を解放できる各関数がコールバック関数を受け取る、独特のスタイルでプログラムを作成する必要があることがわかります。このスタイルの専門用語は、「継続渡しスタイル」または「非同期スタイル」です。

于 2012-04-16T19:43:08.523 に答える
2

あなたは多くのものを作ることができます:

  1. ループを最適化します - 重い作業が DOM アクセスと関係がある場合は、この回答を参照してください
    • 関数が何らかの生データを処理している場合は、型付き配列を使用しますMSDN MDN
  2. setTimeout() を使用したメソッドはeterationと呼ばれます。非常に便利です。

  3. 関数は、非関数型プログラミング言語の典型的な非常に単純なようです。JavaScript はコールバックSO questionを利用します。

  4. 新しい機能の 1 つは Web ワーカーMDN MSDN wikipediaです。

  5. 最後に (おそらく)、すべてのメソッドを組み合わせることです。関数が 1 つのスレッドのみを使用する従来の方法を使用します。Web ワーカーを使用できる場合は、作業を複数に分割できます。これにより、タスクを完了するのに必要な時間を最小限に抑えることができます。

于 2012-04-17T12:06:47.880 に答える
2

2 つの方法があります。

a) Html5 機能を使用できます。次に、ワーカー スレッドの使用を検討できます。

b) このタスクを分割し、一度に 1 つの呼び出しを行い、何かすることがある限り反復するメッセージをキューに入れます。

于 2012-04-16T19:31:11.893 に答える
1
function doSomethingHeavy(param){
   if (param && param%100==0) 
     alert(param);
}

(function heavyWork(){
    for (var i=0; i<=300; i++){
       window.setTimeout(
           (function(i){ return function(){doSomethingHeavy(i)}; })(i)
       ,0);
    }
}())
于 2012-04-16T19:29:27.767 に答える
1

そのような重い仕事をするために特定の backgroundtask JavaScript ライブラリを書いた人がいました..あなたはここでこの質問でそれをチェックするかもしれません:

JavaScript でバックグラウンド タスクを実行する

それを自分で使用したことはありません。言及されているスレッドの使用法を使用しただけです。

于 2012-04-16T19:30:26.547 に答える