UIをブロックすることなく配列を反復処理する最良の方法
質問
私はいくつかの大きな配列に対して反復処理を行い、APIコールからバックボーンコレクションにそれらを格納する必要があります。ループがインターフェイスを応答しなくさせることなく、これを行う最良の方法は何ですか?
返されたデータが非常に大きいので、ajaxリクエストのリターンもブロックされます。私はそれを分割して、より小さなチャンクで非同期に実行させるためにsetTimeoutを使用することができると考えていますが、これを行うためのより簡単な方法はありますか。
Web ワーカーが良いと思ったのですが、UI スレッドに保存されたいくつかのデータ構造を変更する必要があります。これを使用して ajax 呼び出しを実行しようとしましたが、UI スレッドにデータを返すときに、インターフェイスが応答しない時間がまだあります。
事前にありがとうございます。
どのように解決するのですか?
webWorkersの有無が選択できます。
WebWorkers を使用しない場合
DOM やアプリ内の他の多くの状態と対話する必要があるコードでは、webWorker を使用できないため、通常の解決策は作業をチャンクに分割し、タイマで作業の各チャンクを実行することです。 タイマーによるチャンク間の中断により、ブラウザ エンジンは進行中の他のイベントを処理することができ、ユーザーの入力が処理されるだけでなく、画面が描画されるようになります。
通常、各タイマーで 1 つ以上処理する余裕があり、タイマーごとに 1 つだけ処理するよりも効率的で高速になります。 このコードは、UI スレッドに各チャンク間の保留中の UI イベントを処理する機会を与え、UI をアクティブに維持します。
function processLargeArray(array) {
// set this to whatever number of items you can process at once
var chunk = 100;
var index = 0;
function doChunk() {
var cnt = chunk;
while (cnt-- && index < array.length) {
// process array[index] here
++index;
}
if (index < array.length) {
// set Timeout for async iteration
setTimeout(doChunk, 1);
}
}
doChunk();
}
processLargeArray(veryLargeArray);
このコンセプトの実用例です。この同じ関数ではなく、別の長時間実行する処理で、同じように
setTimeout()
を使用して、多くの反復を伴う確率シナリオをテストするための、異なる長期的なプロセスです。
http://jsfiddle.net/jfriend00/9hCVq/
上記をより汎用的にして、以下のようなコールバック関数を呼び出すことができます。
.forEach()
はこのようにします。
// last two args are optional
function processLargeArrayAsync(array, fn, chunk, context) {
context = context || window;
chunk = chunk || 100;
var index = 0;
function doChunk() {
var cnt = chunk;
while (cnt-- && index < array.length) {
// callback called with args (value, index, array)
fn.call(context, array[index], index, array);
++index;
}
if (index < array.length) {
// set Timeout for async iteration
setTimeout(doChunk, 1);
}
}
doChunk();
}
processLargeArrayAsync(veryLargeArray, myCallback, 100);
一度にいくつチャンクするかを推測するのではなく、経過時間を各チャンクのガイドとし、与えられた時間間隔でできる限り多く処理させることも可能です。 これにより、反復処理にどれだけCPU負荷がかかっても、ブラウザの応答性がある程度自動的に保証されます。 したがって、チャンクサイズを渡すのではなく、ミリ秒の値を渡すことができます(または、単にインテリジェントなデフォルトを使用します)。
// last two args are optional
function processLargeArrayAsync(array, fn, maxTimePerChunk, context) {
context = context || window;
maxTimePerChunk = maxTimePerChunk || 200;
var index = 0;
function now() {
return new Date().getTime();
}
function doChunk() {
var startTime = now();
while (index < array.length && (now() - startTime) <= maxTimePerChunk) {
// callback called with args (value, index, array)
fn.call(context, array[index], index, array);
++index;
}
if (index < array.length) {
// set Timeout for async iteration
setTimeout(doChunk, 1);
}
}
doChunk();
}
processLargeArrayAsync(veryLargeArray, myCallback);
WebWorkersを使用する
ループ内のコードが DOM にアクセスする必要がない場合、時間のかかるコードをすべて webWorker に置くことができます。 webWorker はメイン ブラウザの Javascript から独立して実行され、終了すると、postMessage ですべての結果を通信することができます。
webWorker は、webWorker で実行されるすべてのコードを別のスクリプト ファイルに分離する必要がありますが、ブラウザ内の他のイベントの処理をブロックする心配がなく、メイン スレッドで長い実行プロセスを行うときに現れるかもしれない "unresponsive script" プロンプトの心配もなく、UI のイベント処理をブロックすることなく完了するまで実行することができます。
関連
-
[解決済み] JavaScriptでオブジェクトをディープクローンする最も効率的な方法は何ですか?
-
[解決済み] ページを再読み込みせずにURLを変更するにはどうすればよいですか?
-
[解決済み] Java の配列を表示する最も簡単な方法は何ですか?
-
[解決済み] JavaScriptで配列の先頭に新しい配列要素を追加するにはどうすればよいですか?
-
[解決済み] モバイル端末の検出にはどのような方法がありますか?
-
[解決済み] 配列の最後の項目を取得する
-
[解決済み] jQueryでJavaScriptオブジェクトから選択する際に、オプションを追加する最も良い方法は何ですか?
-
[解決済み] 新しい配列を作成せずに、既存のJavaScript配列を別の配列で拡張する方法
-
[解決済み] ExtJS 4のイベントハンドリングについて
-
[解決済み] JavaScriptで、ある文字列が別の文字列の中に出現するすべてのインデックスを見つけるにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] URL/アドレスバーからJavascriptの関数を呼び出す
-
[解決済み] JavaScriptで:hoverのCSSプロパティを変更する
-
[解決済み] 無効になっている入力フィールドの値を送信する
-
[解決済み] Javascript / jQueryでAndroid端末を検出する。
-
[解決済み] JavaScriptでの大文字小文字を区別しない正規表現
-
[解決済み] jQueryの$という記号の意味は何ですか?
-
[解決済み] サブドメインにまたがってlocalStorageを使用する
-
[解決済み] TypeScriptプロジェクトで既存のC#クラス定義を再利用する方法
-
[解決済み] AJAX Mailchimp サインアップフォームの統合
-
[解決済み] JavaScriptの文字列プリミティブとStringオブジェクトの違いは何ですか?