Как дождаться завершения jQuery-запроса ajax в цикле?
У меня есть этот код:
for (var i = 0; i < $total_files; i++) {
$.ajax({
type: 'POST',
url: 'uploading.php',
context: $(this),
dataType: 'json',
cache: false,
contentType: false,
processData: false,
data: data_string,
success: function(datas) {
//does something
},
error: function(e) {
alert('error, try again');
}
});
}
Он загружает изображения очень хорошо, но проблема в том, что я не могу найти способ загрузки изображений один за другим, я попытался поместить опцию асинхронно на false, но она замораживает веб-браузер пока все изображения не будут загружены, а это не то, что я хочу, я хочу как-то эмулировать эту опцию "async: false" , чтобы выполнить одно и то же, но не замораживая веб-браузер.
Как это сделать?
Ответы
Ответ 1
Вы можете создать массив promises, чтобы после того, как все promises были разрешены, вы можете запустить свой код all done
.
var promises = [];
for (var i = 0; i < $total_files; i++){
/* $.ajax returns a promise*/
var request = $.ajax({
/* your ajax config*/
})
promises.push( request);
}
$.when.apply(null, promises).done(function(){
alert('All done')
})
DEMO
Ответ 2
Заполните массив каждым вызовом и вызовите следующий элемент, когда выполняется предыдущее.
Вы можете попробовать что-то вроде этого:
window.syncUpload = {
queue : [],
upload : function(imagesCount) {
var $total_files = imagesCount, data_string = "";
/* Populates queue array with all ajax calls you are going to need */
for (var i=0; i < $total_files; i++) {
this.queue.push({
type: 'POST',
url: 'uploading.php',
context: $(this),
dataType: 'json',
cache: false,
contentType: false,
processData: false,
data: data_string,
success: function(datas) {
//does something
},
error: function(e){
alert('error, try again');
},
/* When the ajax finished it'll fire the complete event, so we
call the next image to be uploaded.
*/
complete : function() {
this[0].uploadNext();
}
});
}
this.uploadNext();
},
uploadNext : function() {
var queue = this.queue;
/* If there something left in the array, send it */
if (queue.length > 0) {
/* Create ajax call and remove item from array */
$.ajax(queue.shift(0));
}
}
}
Просто назовите его, используя syncUpload.upload(NUMBER_OF_IMAGES);
Ответ 3
Я бы попробовал jQuery.when, чтобы вы все еще могли использовать асинхронный вызов, но отложили, что-то вроде:
jQuery(document).ready(function ($) {
$.when(
//for (var i = 0; i < $total_files; i++) {
$.ajax({
// ajax code
})
//}
).done(function () {
// perform after ajax loop is done
});
}); // ready
РЕДАКТИРОВАТЬ: ajax-итерация должна выполняться вне $.when
и вставляться в массив, как предложено charlietfl. Вы можете использовать (асинхронный) вызов ajax и отложить его внутри $.when
, хотя см. JSFIDDLE
Ответ 4
Для jQuery 3.x + и современного браузера, поддерживающего родной Promise
, Promise.all
, можно использовать этот способ:
var promises = [];
for (var i = 0; i < $total_files; i++) {
// jQuery returns a prom
promises.push($.ajax({
/* your ajax config*/
}))
}
Promise.all(promises)
.then(responseList => {
console.dir(responseList)
})
Если ваши файлы уже сохранены в списке, вы можете использовать map
вместо цикла.
var fileList = [/*... list of files ...*/];
Promise.all(fileList.map(file => $.ajax({
/* your ajax config*/
})))
.then(responseList => {
console.dir(responseList)
})
Ответ 5
В одном утверждении с jquery
$.when.apply(null, $.map(/*input Array|jQuery*/, function (n, i) {
return $.get(/* URL */, function (data) {
/* Do something */
});
})).done(function () {
/* Called after all ajax is done */
});
Ответ 6
Вы должны отменить свою зависимость от кода. Поскольку AJAX - это вызов ASYNCHRONOUS, тогда цикл не будет ждать завершения предыдущего вызова.
Вы должны отправить еще один AJAX только тогда, когда ваш предыдущий закончен с помощью функции успеха и подсчитайте общее количество загруженных файлов.
Так же:
$total_files = 5;
$total_files_uploaded = 0;
// Pass parameter to function if needed or get it from higher scope
function uploadFile() {
if ( $total_files_uploaded == $total_files ) return;
$.ajax({
type: 'POST',
url: 'uploading.php',
context: $(this),
dataType: 'json',
cache: false,
contentType: false,
processData: false,
data: data_string,
success: function(datas) {
// if finished, do another round of upload
$total_files_uploaded++;
uploadFile();
},
error: function(e){
alert('error, try again');
}
});
}
Я не уверен, что вы передаете в $(это), но убедитесь, что он прошел с каждым вызовом функции.