Почему мой javascript/jquery не выполняется последовательно?

У меня есть кнопка, привязанная к обработчику кликов, который делает один или несколько вызовов AJAX, в зависимости от того, сколько элементов находится в массиве. Я использую плагин jquery blockUI, чтобы показать сообщение во время вызова(ов) ajax, затем Я показываю результаты и удаляю сообщение blockUI, вызывая $.unblockUI();.

Проблема: по какой-то причине, независимо от того, сколько раз я хочу, чтобы функция ajaxCall выполнялась, после завершения ПЕРВОГО вызова ajax обмен сообщениями удаляется, хотя цикл все еще продолжает выполняться, и отображаются результаты. правильно в разделе #results. Я хочу, чтобы полное количество итераций цикла завершилось перед удалением сообщений, но похоже, что оно не выполняется последовательно. Вот рассматриваемый код:

$("#myButton").live("click", function(){
    $.blockUI({ message: '<img src="new_loader.gif" /><h2>Getting Config Files</h2><small>Please be patient.</small>',
            css: { 
            border: 'none', 
            padding: '15px', 
            backgroundColor: '#FFF', 
            '-webkit-border-radius': '10px', 
            '-moz-border-radius': '10px',  
            color: '#000' 
            } 
        }); 

    for (var i=0; i< myArray.length; i++)
        {
         ajaxCall(myArray[i]);
        }
    $("#results").show('slow');
    $.unblockUI();  
    return false;
});

Есть ли объяснение, почему код ПОСЛЕ цикла выполняется, хотя цикл еще не завершен? Любая помощь приветствуется! Спасибо.


person tresstylez    schedule 31.01.2011    source источник
comment
Вы уверены, что цикл не завершился? Вызовы Ajax занимают некоторое время, если они все еще выполняются, цикл может быть завершен.   -  person goto-bus-stop    schedule 31.01.2011
comment
Вам было бы лучше сделать один запрос с полным сериализованным массивом и разблокировать интерфейс в обратном вызове (единственного) запроса.   -  person karim79    schedule 31.01.2011


Ответы (3)


 ajaxCall(myArray[i]);

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

хороший способ справиться с таким поведением можно найти в этой статье: Очередь асинхронных методов цепочка в JavaScript

person Caspar Kleijne    schedule 31.01.2011

Что бы ни делал ajaxCall(), если он создает XMLHttpRequest асинхронно, это правильное поведение. Запрос Ajax по умолчанию является неблокирующим, я думаю, именно поэтому ваш код после вашего цикла выполняется немедленно.

Один из возможных способов решить эту проблему — создать переменную-счетчик, которая увеличивается при каждом вызове из ajaxCall() и уменьшается в каждом обработчике complete (состояние готовности XHR 4). Когда этот счетчик достигает нуля, вы должны выполнить свой код после цикла.

function increase() {      // goes into your `ajaxCall()` or `beforeSend` callback
    mynamespace.requests++;
}

function decrease() {      // goes into your `complete` callbacks
    if(--mynamespace.requests) {
        $("#results").show('slow');
        $.unblockUI();  
    }
}
person jAndy    schedule 31.01.2011
comment
Здесь снижение должно было бы быть вызвано дважды. Вам нужно вычесть, прежде чем проверять, равно ли оно нулю. - person Josh K; 31.01.2011

Я предполагаю, что ajaxCall асинхронный? Это приведет к тому, что код не будет блокироваться в цикле, по сути, быстро завершая цикл, а затем продолжая его.

Что вы можете сделать, так это предоставить функцию обратного вызова со счетчиком, чтобы проверить, завершены ли все вызовы ajax.

var count = arr.length - 1;
for(var i = 0; i < arr.length; i++)
{
    ajaxCall(arr[i], function () {
        if(--count == 0)
        {
            /* All AJAX calls complete, continue execution */
        }
    });
}
person Josh K    schedule 31.01.2011