Вы можете использовать jQuery .when
, чтобы отложить действие до окончания все AJAX просит завершить.
Что-то вроде этого:
function updateHandler()
{
var promisesArray = [];
var successCounter = 0;
var promise;
$.each(testarray, function(k, valu)
{
var count = testarray.length;
var checkloop = k+1;
var valkor = "/webresources/api/v3/sites/current/pages/" + valu.value;
var valkis = valu.checkbox;
promise =
$.ajax(
{
url: valkor,
processData: false,
data: JSON.stringify({ "enabled" : valkis }),
type: "PUT",
contentType: "application/json",
mimeType: "application/json ",
headers: { "Authorization": $.cookie('access_token') },
});
promise.done(function(msg)
{
console.log("successfully updated");
successCounter++;
});
promise.fail(function(jqXHR) { /* error out... */ });
promisesArray.push(promise);
});
$.when.apply($, promisesArray).done(function()
{
location.reload(true);
console.log("WAITED FOR " + successCounter + " OF " + testarray.length);
});
}
$('#update1').click(updateHandler);
Обратитесь к документации для $.when
.
Поскольку jQuery 1,5, звонки, подобные $.ajax
, возвращают обещание. Они полезны для разных вещей (см. this post для других полезных вещей о обещаниях), но в нашем случае мы хотели бы собрать обещания подать на звонок $.when
, чтобы отложить выполнение фрагмента кода пока все запросы AJAX не возвратят ответ.
В цикле $.each
мы определяем вызовы $.ajax
. Как только каждый из них определяется - после каждого звонка до $.ajax
- запрос отправляется по сети, и браузер будет ждать ответа. Кроме того, мы собираем связанный обещание для каждого отдельного вызова $.ajax
в переменной. В приведенном выше коде мы выполняем две вещи с каждым из этих обещаний: 1) добавляем индивидуальные done
и error
функции для принятия мер - по индивидуальному запросу - после завершения каждого вызова; 2) мы сохраняем обещание в promisesArray
, чтобы мы могли принять меры только после того, как все звонки завершены.
Важная вещь, чтобы отметить здесь, что эта строка: promise = $.ajax(...
не сохраняет результат - то есть ответ - вызова AJAX, он сохраняет обещание, связанное с вызовом AJAX.
Наконец, мы передаем эти обещания $.when
, который использует свою собственную функцию done
, чтобы выполнить действие, которое мы хотим предпринять, только после того, как все вызовы AJAX вернулись.
Решение выше собирает множество обещаний, поскольку мое предположение из вашего вопроса и ваше использование testarray
заключается в том, что мы не знаем заранее, сколько вызовов AJAX будет необходимо. Если вы сделали знать, сколько AJAX вызовов, которые вы будете использовать, мы можем удалить promisesArray
из раствора, который может выглядеть примерно так и в случае 3 AJAX звонков:
$.when(
$.ajax(/* args for 1st call */).done(/* 1st call success code */),
$.ajax(/* args for 2nd call */).done(/* 2nd call success code */),
$.ajax(/* args for 3rd call */).done(/* 3rd call success code */)
).done(function()
{
location.reload(true);
});
Поскольку мы не знаем как необходимо много вызовов, напримериз-за пользовательского ввода, нам нужно собрать обещания, связанные с неизвестным номером звонков $.ajax
.
Перед JQuery поддерживается отложенное выполнение - перед JQuery 1.5 - еще один способ справиться с проблемой принять меры только после того, как эти другие N (обычно AJAX) действий полных была держать большое переменное состояние: с N действиями для завершения вы создаете массив из N булевых элементов. Когда каждое действие завершено (вызов AJAX возвращен), обработчик done
выполнил бы две вещи: 1) установить его флаг в true
; 2) проверьте, установлены ли все, флаги установлены на true
, а затем выполните действие, например, для повторной загрузки страницы. Это работало из-за однопоточного характера обработки очереди событий JavaScript.
Есть еще несколько вещей, чтобы отметить здесь:
- вам нужны
apply
потому $.when
ожидает deferreds как отдельные параметры.
- Я добавил счетчик, который увеличивается на каждом звонке AJAX
done
, если вы закомментируете звонок location.reload
, вы должны увидеть - при условии, что вызовы PUT успешны - значение счетчика соответствует размеру testarray
.
- вы должны учитывать разницу между использованием
$.when().done
против $.when().always()
, чтобы определить, что лучше подходит для вашего собственного кода.
- Я потянул установку цепей
$.each
и $.when
в отдельную функцию. Это несущественно, и вы можете оставить их в click
, как в вашем исходном коде, и он все равно будет работать.
- Я проверял это, добавив кнопку с update1 как
id
и нажав на https://httpbin/put в качестве вашего valkor
URL.
Как правило, не используйте async: false;
- когда вы делаете это, всегда создавайте резервную копию и ищите другой способ. jQuery/JavaScript всегда предоставляет один.
Вы действительно не должны использовать 'асинхронные: false' при принятии AJAX звонков, как это может вызвать всевозможные неприятные побочные эффекты так как весь ваш код по существу будет «застрял», ожидая завершения каждого запроса (и он полностью победит цель A в AJAX). –
Спасибо, Рон, если я не использую async: false, тогда страница перезагружается, даже если каждый цикл не завершится. В любом случае мы можем обновить страницу после завершения цикла .each. –