Как узнать, завершился ли XMLHttpRequest? - PullRequest
0 голосов
/ 08 октября 2019

Я загружаю несколько файлов с полем формы

<input type="file" accept="image/jpeg, image/png" multiple 

цикл отправляет все файлы для загрузки функции

       // Upload photo function
            var upload = function (photo, callback) {
                var formData = new FormData();
                formData.append('photo', photo);
                var request = new XMLHttpRequest();
                request.onreadystatechange = function() {
                    if (request.readyState === 4) {
                        callback(request.response);
                    }
                }
                request.open('POST', 'upload.php');
                request.responseType = 'json';
                request.send(formData);
            };  


    for (var i = 0; i < files.length; i++) {
        upload(resizedFile, function (response) { });
    }

, если все файлы успешно загружены, хотите перенаправить ..

//all files finished, go to ...
if(response !== null && typeof response !== 'object') var response = JSON.parse(response);
window.location.href = "my-new-url.php?id="+response.id;

моя проблема, перенаправление выполняется до завершения всех загрузок. как я могу заставить скрипт ждать завершения всех xmlhttprequests?


EDIT

Я изменил функцию загрузки следующим образом, чтобы загрузить с помощью jQuery. Функция fuction вызывается несколько раз из цикла for, так как я могу дождаться завершения всех вызовов loop / jquery, а затем перенаправить?

function upload (photo, callback) {
        var fd = new FormData();
        fd.append('photo',photo);

        return $.ajax({
            url: 'upload.php',
            type: 'post',
            data: fd,
            contentType: false,
            processData: false,
            success: function(response){

            },
        });
    };

Ответы [ 2 ]

1 голос
/ 08 октября 2019

Прежде всего, я бы обещал функцию загрузки. С JQuery было бы намного короче, так как $.ajax возвращает объект, доступный для просмотра, но со старомодным ванильным JS, это выглядело бы так:

var upload = function (photo) {
    return new Promise(function(resolve, reject) {
        var request = new XMLHttpRequest();

        request.onload = function() {
            if (request.status >= 200 && request.status < 300) {
                resolve(request.response);
            } else {
                reject(request.statusText);
            }
        };      
        request.onerror = function() { reject(request.statusText) }
        request.open('POST', 'upload.php');
        request.responseType = 'json';

        var formData = new FormData();
        formData.append('photo', photo);
        request.send(formData);
    })
}

См. Также: http://ccoenraets.github.io/es6-tutorial-data/promisify/

Затем я собираю эти обещания в массиве:

var uploads = files.map(function(file) { return upload(resizeFile(file)); })

(или просто повторяю, как вы сделали, и помещаю их в массив)

Затем вы можете использовать этот код для обработки завершениявсе загрузки:

Promise.all(uploads)
   .then(function(results) { /* do the redirect */ })
   .catch(function(error) { console.log(error); });

См. также: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Примечание: Почему подсчет предлагается в другом ответе неправильно? Потому что он не обрабатывает условие, когда любой из запросов не выполняется. Вы не сможете обнаружить этот случай, и вы никогда не достигнете условия, которое будет удовлетворено. Обещания (и async / await) являются правильным способом обработки асинхронных операций, таких как запросы ajax.

[Update]

Вот подход JQuery с использованием новейшей JSОсобенности языка:

var upload = (photo) => {
   photo = resizeFile(photo);

   let formData = new FormData();
   formData.append('photo', photo);
   return $.ajax({
     type: 'POST',
     url: 'upload.php',
     data: formData
   }) // check other the options of ajax method, you might need them
}

let uploads = files.map(upload);

$.when.apply($,uploads)
  .done(_ => { /* do the redirect */ })
  .fail(e => { /* handle error */ })

Последняя часть может быть написана с синтаксисом async/await:

async somefunction(){ 

  // rest of the code

  try {
     await $.when.apply($,uploads)
     /* do the redirect */
  } catch(ex) {
     /* handle error */
  }
}

Обратите внимание, что $.ajax возвращает Отложено , чтообъект JQuery, совместимый с Promise.

1 голос
/ 08 октября 2019

Вы можете увеличить переменную глобального счетчика в обратном вызове. Когда он достигает длины массива, все запросы завершены.

var completed = 0;
for (var i = 0; i < files.length; i++) {
    upload(resizedFile, function (response) {
        if (++completed == files.length) {
            window.location = redirect_url;
        }
    });
}
...