解決策は少し注意が必要ですが、問題は実際にはかなり単純です。「フリーズ」が発生している理由は、JavaScriptがシングルスレッドであるためです。ページの描画は、データの処理と同じスレッドで行われます。そのため、処理に時間がかかるデータのチャンクが1つある場合、ユーザーインターフェイスがフリーズすることがあります。
次の例を考えてみましょう。
http://jsfiddle.net/VT4Rs/
注:「STOP」ボタンをクリックしたときに画面がフリーズした場合は、「STOP」ボタンを少しスパムする必要があるかもしれません。また、「WEIGHT」変数を調整して、コンピューター/ブラウザーが私のものよりも優れていない場合に超長時間のフリーズを防止したり、コンピューター/ブラウザーが私のものよりも優れている場合にフリーズを発生させたりする必要がある場合があります。
とにかく、ポイントは、「時計」がそれらすべての番号をループしている間、定期的にフリーズすることに気付くでしょう。これは、データの「処理」と同じスレッドでクロックの更新が行われているためです。この方法では、ミリ秒setInterval()
ごとにイベントを(渡された関数を実行するために)イベントキューに追加します。X
ただし、関数の実行にミリ秒以上かかる状況からの深刻な問題を防ぐためにX
、イベントの前の反復がすでにキューにある場合は、イベントキューへの新しいイベントの追加をスキップします。
したがって、スレッドを占有しているランダムな処理がある場合、setInterval
sは明らかに正しく機能しません。また、ブラウザのインターフェースは同じスレッドで更新されるため、「フリーズ」を引き起こす可能性もあります。
これを解決するために私が見つけた最善の方法は、データ処理をより管理しやすい「チャンク」にsetTimeout(fn, 0)
分割し、ブラウザのペイントやその他のJavaScriptで必要に応じて処理できるようにしながら、それらのチャンクを定期的にイベントキューにプッシュすることです。したがって、この更新された例を見て、違いを確認してください。同じデータをまだ「処理」していますが、データを小さなチャンクに分割しています。
http://jsfiddle.net/Sjk29/
秘訣は、チャンクを作成する大きさを決定することです。チャンクを大きくしすぎると、ストールや間隔の欠落が発生することがわかります。ただし、小さすぎると、各チャンクのオーバーヘッドが組み込まれているため、データの処理に永遠に時間がかかります。
良いニュースは、指定されたサイズに制限されていないことです。私の例では、チャンクサイズは変数によって決定され、変数が各チャンクを参照していることに気付くかもしれません。これは、ユーザーのブラウザーでの実際のパフォーマンスに応じて、その変数を調整してチャンクサイズを調整できることを意味します。あなたはこのようなことをするかもしれません:
var CHUNK_SCALE = 8;
var CHUNK_SIZE = function() { return Math.pow(10, CHUNK_SCALE); };
(function() {
var lastTick = new Date();
setInterval(function() {
var now = new Date();
if (now - lastTick > 1500) {
CHUNK_SCALE--;
}
lastTick = now;
}, 1000);
}());
(参照: http: //jsfiddle.net/ewP96/)
このように、チャンクサイズが(UIパフォーマンスに影響を与える可能性のある方法で)大きすぎる場合、ユーザーのコンピューターが処理できるサイズに自動的に縮小されます。
JavaScriptはかなり素晴らしいですよね?