如何知道XMLHttpRequest是否已完成?

问题描述 投票:0回答:2

我正在使用表单字段上载多个文件

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

我的问题,重定向是在所有上传完成之前完成的。如何使脚本等待所有xmlhttprequest完成?


编辑

我更改了这样的上传功能,以使用jQuery进行上传。功能从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){

            },
        });
    };
javascript jquery upload xmlhttprequest photo
2个回答
1
投票
您可以在回调中增加全局计数器变量。当它达到数组的长度时,所有请求都已完成。

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


1
投票
首先,我会

promisify上传功能。使用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

注:为什么在另一个答案中建议计数错误?因为当任何请求失败时,它不会处理条件。您将无法检测到这种情况,也永远无法达到满足的条件。承诺(和异步/等待)是处理异步操作(如ajax请求)的正确方法。

[更新]

这里是使用最新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 */ })

后一部分可以用async/await语法编写:

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

注意,$.ajax返回Deferred,它是与Promise兼容的JQuery对象。
© www.soinside.com 2019 - 2024. All rights reserved.