jQuery, как сделать ajax-запрос "синхронным", когда async имеет значение true - PullRequest
1 голос
/ 14 марта 2012
var tds = ["0", "1", "2", "3", "4", "5", "6"];

for (var i = 0; i < tds.length; i++) {

    jQuery("#notification-bar").html('I am doing ' + tds[i]);

    jQuery.ajax({
        url: "/ajax_json_echo/",
        type: "POST",
        timeout: 10000,
        data: tds[i],
        success: function(response) {

        },
        error: function(x, t, m) {


        }
    });


} //end for

jQuery("#notification-bar").html("Done!");​

/ ajax_json_echo / может потребоваться 10 секунд или даже больше, чтобы справиться с tds.

Ожидаемый результат панели уведомлений

Я делаю 0

Я делаю 1

Я делаю 2

...

Готово!

Фактический результат, который я получаю:

Готово!

Я полагаю, это вызвано тем, что переменная async в jquery ajax установлена ​​в true.

Если установлено значение false, браузер будет заморожен. Когда он восстанавливается, я получаю "Готово!" только.

Ответы [ 5 ]

3 голосов
/ 14 марта 2012

Браузер запускает JavaScript и выполняет рендеринг страниц в одном и том же потоке, поэтому во время работы JS перерисовки не произойдет. Это означает, что весь цикл for завершится, и сообщение о состоянии будет установлено как «Готово!» до страница обновляется.

В случае, если асинхронность истинна, все Ajax-запросы изначально ставятся в очередь, а для сообщения устанавливается значение «Готово!» и затем ответы обрабатываются позже асинхронно. В случае, если для асинхронного режима установлено значение false, запросы Ajax выполняются по одному за раз без каких-либо дополнительных действий до тех пор, пока не поступит ответ. В любом случае браузер никогда не получает возможности отобразить сообщения «Я делаю ...».

Вместо использования цикла вы можете инициировать каждый последующий вызов из полного (или успешного) обратного вызова Ajax:

var tds = ["0", "1", "2", "3", "4", "5", "6"];

function doNextAjax(i) {
   if (i < tds.length) {
      jQuery("#notification-bar").html('I am doing ' + tds[i]);

      jQuery.ajax({
         url: "/ajax_json_echo/",
         type: "POST",
         timeout: 10000,
         data: tds[i],
         success: function(response) {

         },
         error: function(x, t, m) {    

         },
         complete: function() {
            doNextAjax(i + 1);
         }
      });
   } else {
      jQuery("#notification-bar").html("Done!");​
   }
}

doNextAjax(0);

Каждый раз, когда вызывается doNextAjax(), он обновляет сообщение о состоянии и делает один Ajax-запрос, и все. Когда функция выходит из браузера, у нее появляется возможность повторно выполнить рендеринг и фактически показать это сообщение. Затем, когда завершается полный обратный вызов, он снова вызывает функцию для следующего элемента. Когда ничего не осталось, он устанавливает "Готово!" сообщение.

Обратите внимание, что использование полного обратного вызова для запуска следующего вызова Ajax означает, что он будет продолжаться даже в случае сбоя определенного запроса. Если вы хотите остановиться на ошибке, вы можете избавиться от полного обработчика и переместить doNextAjax(i+1) в обратный вызов успеха.

0 голосов
/ 14 марта 2012

Вот решение, вы должны взглянуть на jQuery deffered object

$.when($.ajax("/page1.php"), $.ajax("/page2.php")).done(function(a1,  a2){
    /* a1 and a2 are arguments resolved for the 
        page1 and page2 ajax requests, respectively */
   var jqXHR = a1[2]; /* arguments are [ "success", statusText, jqXHR ] */
   if ( /Whip It/.test(jqXHR.responseText) ) {
      alert("First page has 'Whip It' somewhere.");
   }
});

http://api.jquery.com/jQuery.when/

0 голосов
/ 14 марта 2012

Ответ, который вы написали, произойдет. Изменение

jQuery("#notification-bar").html('I am doing ' + tds[i]);
jQuery("#notification-bar").html("Done!");​

до

jQuery("#notification-bar").append('I am doing ' + tds[i]);
jQuery("#notification-bar").append("Done!");​

и вы увидите результат. Но поведение не то, что вы ожидаете. Цикл for запускает все AJAX-вызовы один за другим. Если вы хотите запустить следующий AJAX-вызов только после завершения последнего, вы должны использовать jQuery Deferred объекты для управления этим.

Я завернул пример здесь http://jsfiddle.net/DXYZw/2/

var tds = ["0", "1", "2", "3", "4", "5", "6"];

var sendRequest = function(ary, data) {
    if (!ary.length) {
        // no more calls to be made
        jQuery("#notification-bar").append("Done!");
        return;
    }
    jQuery("#notification-bar").append('I am doing ' + tds.length);
    dfAJAX(ary)
        .done(sendRequest)
        .fail(function() {
            alert("error");
        });
}

var dfAJAX = function(ary) {
    var dfd = new jQuery.Deferred();

    var dataToSend = ary.pop();

    jQuery.ajax({
        url: "/ajax_json_echo/",
        type: "POST",
        timeout: 10000,
        data: dataToSend
    })
        .done(function(data) {
            dfd.resolve(ary, data);
        })
        .fail(function() {
            dfd.reject();
        })

    return dfd.promise();
}

sendRequest(tds);
0 голосов
/ 14 марта 2012

Если вы можете использовать элементы HTML5, используйте элемент <progress>, поэтому он там.
Увеличьте значение индикатора выполнения в обратном вызове успеха каждого ajax-запроса.

var progress = document.getElementById('progress');
progress.max = tds.length;  

...
success: function(){
                       progress.value++;
                   }

LIVE DEMO

0 голосов
/ 14 марта 2012

Обычно это то, что вы используете параметр обратного вызова success для ajax() для - для запуска функции после завершения запроса AJAX.

http://api.jquery.com/jQuery.ajax/

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