Вызов асинхронной функции jQuery, без запроса AJAX - PullRequest
40 голосов
/ 27 июля 2011

Это кажется глупым, но я не могу найти, как сделать асинхронный вызов функции с 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 завершается.

Редактировать: Я использовал ответ Вивина , в частности, Ссылка Sitepoint , чтобы получить следующее решение:

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 скрываются, когда они работают, и именно к этому я стремился.

Ответы [ 3 ]

30 голосов
/ 27 июля 2011

Javascript выполняется в одном потоке, и поэтому, если у вас медленная функция, он будет блокировать все остальное.

ОБНОВЛЕНИЕ

Это будетделайте то, что вы хотите, но имейте в виду, что они не широко поддерживаются поддерживаются в IE (я думаю, они будут в IE10).

Некоторые ресурсы по веб-работникам:

Вот несколько ресурсов по выполнению многопоточности без веб-работников.Важно отметить, что это не «истинная» многопоточность:

6 голосов
/ 27 июля 2011

Я собирался предложить посмотреть на тайм-аут, но увы. Этот пост Джона Резига (из jQuery) объясняет, как JavaScript обрабатывает свою единственную нить. http://ejohn.org/blog/how-javascript-timers-work/

В этой статье также объясняется: «При выполнении асинхронных функций в JavaScript нужно помнить одну вещь: все остальные операции JavaScript на странице приостанавливаются до завершения вызова функции. Так выполняются все текущие браузеры. 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)
5 голосов
/ 27 июля 2011

Возможно, вы захотите веб-работников!

Редактировать: Я удивлен, сколько людей прыгнуло на "это невозможно", поэтому я уточню.Веб-работники являются частью HTML 5 spec .Они позволяют создавать потоки для запуска сценариев в фоновом режиме, не блокируя пользовательский интерфейс.Это должны быть внешние js-файлы, которые вызываются

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

и передаются через события.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...