web-dev-qa-db-ja.com

jQuery非同期関数呼び出し、no AJAX request

これはばかげているように思えますが、サーバー側の要求を伴わないjQueryで非同期関数呼び出しを行う方法を見つけることができません。多くのDOM要素を反復処理する遅い関数があり、この関数の実行中にブラウザーがフリーズしないようにしたい。スロー関数が呼び出される前に小さなインジケーターを表示し、スロー関数が戻ったときにインジケーターを非表示にします。私は次のものを持っています:

$('form#filter', parentNode).submit(function() {
  var form = $(this);
  indicator.show();
  var textField = $('input#query', form);
  var query = jQuery.trim(textField.val());
  var re = new RegExp(query, "i");
  slowFunctionCall(); // want this to happen asynchronously; all client-side
  indicator.hide();
  return false;
});

現在、フォームを送信しますが、インジケーターは表示されず、ブラウザーがフリーズし、slowFunctionCallが終了します。

編集:Vivin's answer 、具体的には Sitepoint link を使用して、次のソリューションを取得しました。

var indicator = $('#tagFilter_loading', parentNode);
indicator.hide();
var spans = $('div#filterResults span', parentNode);
var textField = $('input#query', parentNode);
var timer = undefined, processor = undefined;
var i=0, limit=spans.length, busy=false;
var filterTags = function() {
  i = 0;
  if (processor) {
    clearInterval(processor);
  }
  indicator.show();
  processor = setInterval(function() {
    if (!busy) {
      busy = true;
      var query = jQuery.trim(textField.val()).toLowerCase();
      var span = $(spans[i]);
      if ('' == query) {
        span.show();
      } else {
        var tagName = span.attr('rel').toLowerCase();
        if (tagName.indexOf(query) == -1) {
          span.hide();
        }
      }
      if (++i >= limit) {
        clearInterval(processor);
        indicator.hide();
      }
      busy = false;
    }
  }, 1);
};
textField.keyup(function() {
  if (timer) {
    clearTimeout(timer);
  }
  /* Only start filtering after the user has finished typing */
  timer = setTimeout(filterTags, 2000);
});
textField.blur(filterTags);

これにより、インジケーターの表示と非表示が切り替わり、ブラウザーがフリーズすることもありません。 DOM要素が機能するときに非表示になっているのを見ることができます。

41
Sarah Vessels

Javascriptは単一のスレッドで実行されるため、遅い関数を使用している場合、willは他のすべてをブロックします。

[〜#〜] update [〜#〜]

それはあなたが望むもののいくつかを行いますが、それらはそうではないことに留意してください 広くサポートされている IEでサポートされています(IE10でサポートされる予定です).

Web Workersに関するいくつかのリソース:

Webワーカーなしでマルチスレッドを達成するためのリソースをいくつか紹介します。これは「真の」マルチスレッドではないことに注意することが重要です。

30
Vivin Paliath

残念ながら、タイムアウトを確認することをお勧めします。 (jQueryの)John Resigによるこの投稿では、JavaScriptがその単一スレッドを処理する方法について少し説明しています。 http://ejohn.org/blog/how-javascript-timers-work/

この記事 も説明しています:「JavaScriptで関数を非同期に実行する際に覚えておくべきことの1つは、関数呼び出しが完了するまでページ内の他のすべてのJavaScriptの実行が停止することです。同時に非同期に多くのことを呼び出そうとすると、実際のパフォーマンスの問題が発生する可能性があります。長時間実行される関数は、実際にユーザーのブラウザを「ロックアップ」します。同じことが同期関数呼び出しにも当てはまります。

とはいえ、ループを小さなチャンクに分割してsetTimeout()を使用することで、非同期関数呼び出しを自分でシミュレートすることができます。

たとえば、この関数:

// Sync
(function() {
  for(var x = 0; x < 100000; ++x) {console.log(x)}
})()

// ASync
var x = 0;
setTimeout(function() {
   console.log(x++);
   if(x < 100000) setTimeout(arguments.callee, 1);
} ,1)
6
slifty

web workers!

編集:私は何人が「不可能」に飛びついたのか驚いたので、詳しく説明します。 Web Workersは HTML 5仕様 の一部です。 UIをブロックすることなく、バックグラウンドでスクリプトを実行するスレッドを生成できます。これらは外部jsファイルである必要があり、

var worker = new Worker('my_task.js');

イベントを介して通信されます。

5
nwellcome