Подтвердить что ты не робот

Как дождаться завершения 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" , чтобы выполнить одно и то же, но не замораживая веб-браузер.

Как это сделать?

4b9b3361

Ответ 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');
            }
        });
    }

Я не уверен, что вы передаете в $(это), но убедитесь, что он прошел с каждым вызовом функции.