Синхронизированные Ajax-запросы с jQuery в цикле

#ajax #jquery #synchronization

#ajax #jquery #синхронизация

Вопрос:

У меня следующая ситуация: мне нужно выполнять синхронизированные Ajax-запросы в цикле и отображать возвращенный результат после каждой итерации в div-элементе (добавляемом сверху с предыдущими результатами внизу). Время отклика каждого запроса может отличаться, но порядок, в котором они должны отображаться, должен быть таким же, как и выданный. Вот пример с 3 запросами. Допустим, для запроса «A» требуется 3 секунды, «B» — 1 секунда, а «C» — 5 секунд. Порядок, в котором я хочу отобразить результат, — A, B, C по мере выдачи запросов, но код, который я использую, показывает результаты в B, A, C.

Вот код (запрос jQuery Ajax):

 $(document).ready(function(){ 
  var json = document.getElementById("hCategories").value;
  var categories = eval( '('   json   ')' );

  for(curCat in categories) {
    curCatKey = categories[curCat]['grKey'];

    $.ajax({
      type: "POST",
      url: "get_results.php",
      data: "category="   escape(curCatKey)   
            "amp;search="   escape($("#hQuery").val()),
      timeout: 8000,
      async: false, 

      success: function(data) {
        $("#content").append(data);
      }
  });
});
  

Я думал, что это будет работать с «async:false», но затем он ожидает завершения каждого вызова Ajax и представляет результаты после цикла. Я надеюсь, что некоторые из вас могут указать на некоторые другие решения, я в значительной степени застрял.

Заранее спасибо, приветствую Криса

РЕДАКТИРОВАТЬ: Спасибо за все возможные решения, я попробую их сейчас одно за другим и вернусь с тем, которое соответствует моей проблеме.

Комментарии:

1. Разве вы не можете использовать обратные вызовы или сортировать их впоследствии по идентификатору? AJAX — это, конечно, асинхронный JavaScript и XML.

2. Вы собираетесь заморозить пользовательский интерфейс на 8 секунд в ожидании результатов? Вы не можете быть серьезны.

Ответ №1:

У меня есть два предложения по решению этой проблемы:

Заполнение сгенерированных divs

Вы могли бы генерировать divs с идентификаторами в цикле и заполнять их по завершении запроса:

 $(document).ready(function() {
    var json = document.getElementById("hCategories").value;
    var categories = eval('('   json   ')');

    for (curCat in categories) {
        (function(curCat) {
            var curCatKey = categories[curCat]['grKey'];
            $('#content').append('<div id="category-"'   escape(curCat)   '/>');

            $.ajax({
                type: "POST",
                url: "get_results.php",
                data: "category="   escape(curCatKey)   "amp;search="   escape($("#hQuery").val()),

                success: function(data) {
                    $("#category-"   escape(curCat)).html(data);
                }
            });
        })(curCat);
    }
});
  

Или используйте отложенный

Вы можете сохранить объекты jqXHR в массиве и использовать отложенный вызов для успешного выполнения функций по порядку, когда все вызовы завершатся.

 $(document).ready(function() {
    var json = document.getElementById("hCategories").value;
    var categories = eval('('   json   ')');
    var requests;

    for (curCat in categories) {
        var curCatKey = categories[curCat]['grKey'];

        requests.push($.ajax({
            type: "POST",
            url: "get_results.php",
            data: "category="   escape(curCatKey)   "amp;search="   escape($("#hQuery").val())
        }));
    }

    $.when.apply(requests).done(function() {
        for (i in requests) {
            requests[i].success(function(data) {
                $("#content").append(data);
            });
        }
    });
});
  

Преимущество первого метода в том, что он непрерывно заполняет контейнеры. Я не тестировал ни одну из этих функций, но логика должна работать так, как я ее описал.

Ответ №2:

Это сделало бы свое дело

 var results = [];
var idx = 0;

for(curCat in categories) {
    curCatKey = categories[curCat]['grKey'];

    (function( i ) {
        $.ajax({
          type: "POST",
          url: "get_results.php",
          data: "category="   escape(curCatKey)   
              "amp;search="   escape($("#hQuery").val()),
          timeout: 8000,
          async: false, 
          success: function(data) {
            results[i] = data;
            if (i == idx - 1) { // last one
               for (var j=0; j < results.length; j  ) {
                   $("#content").append(results[j]);
               }
            }
          }
       });
    })(idx  );
  

Ответ №3:

Я думаю, что что-то вроде этого — это то, что вы ищете. Возможно, потребуется некоторая настройка, я немного устал от Deferred. Однако почитайте об этом, очень мощный

 deferred = $.Deferred()
for(curCat in categories) {
  deferred.pipe(
    function(resp){
      postData = {} // set up your data...
      return $.post("get_results.php", {data: postData, timeout: 8000})
              .done(function(content){ $("#content").append(content) })
    })
  )
}

// Trigger the whole chain of requests
deferred.resolve()