简体   繁体   English

如何知道XMLHttpRequest是否完成?

[英]How to know if XMLHttpRequest has finished?

I'm uploading multiple files with form field我正在使用表单字段上传多个文件

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

a loop sends all files to upload function一个循环发送所有文件上传 function

       // 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) { });
    }

if all files are successfully uploaded, want to redirect..如果所有文件都成功上传,想要重定向..

//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;

my problem, the redirect is done before all uploads are finished.我的问题,重定向是在所有上传完成之前完成的。 how can I make the script wait for all xmlhttprequests to finish?如何让脚本等待所有 xmlhttprequests 完成?


EDIT编辑

I changed the upload function like this, to upload with jQuery.我像这样将上传 function 更改为使用 jQuery 上传。 The fuction is called several times from the for loop, so how can I wait for all loops/jquery calls are finished, then redirect?从 for 循环中多次调用该函数,那么我如何等待所有循环/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){

            },
        });
    };

You can increment a global counter variable in the callback.您可以在回调中增加一个全局计数器变量。 When it reaches the length of the array, all the requests have completed.当它达到数组的长度时,所有的请求都完成了。

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

First of all, I would promisify the upload function.首先,我会承诺上传function With JQuery would be much shorter as $.ajax returns a thenable object, but with old-fashioned vanilla JS, it would look like this:使用 JQuery 会更短,因为$.ajax返回一个可用的 object,但使用老式香草 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);
    })
}

See also: http://ccoenraets.github.io/es6-tutorial-data/promisify/另见: http://ccoenraets.github.io/es6-tutorial-data/promisify/

Then I would collect these promises in an array:然后我会在一个数组中收集这些承诺:

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

(or simply iterate as you did and push them in an array) (或者像你一样简单地迭代并将它们推送到一个数组中)

Then you can use this code to handle the completion of all uploads:然后您可以使用此代码来处理所有上传的完成:

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

See also: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all另请参阅: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Note: Why is counting suggested in an other answer wrong?注意:为什么其他答案中建议的计数错误? Because it does not handle the condition when any of the requests fails.因为它不处理任何请求失败时的条件。 You will not be able to detect that case, and you will never reach the condition to be satisfied.您将无法检测到这种情况,并且您永远不会达到满足的条件。 Promises (and async/await) are the right way of handling asynchronous operations, like ajax requests. Promise(和 async/await)是处理异步操作的正确方法,例如 ajax 请求。

[Update] [更新]

Here is the JQuery approach using the latest JS language features:这是使用最新 JS 语言功能的 JQuery 方法:

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 */ })

The latter part can be written with async/await syntax:后半部分可以用async/await语法编写:

async somefunction(){ 

  // rest of the code

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

Note, that $.ajax returns Deferred , which is a JQuery object, compatible with Promise.请注意, $.ajax返回Deferred ,这是一个 JQuery object,与 ZA5A3F0F5287A44789AZACA42 兼容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM